AppDelegate.mm 17.9 KB
Newer Older
1
/*
Alexandre Lision's avatar
Alexandre Lision committed
2
 *  Copyright (C) 2015-2016 Savoir-faire Linux Inc.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 */
19
#import <SystemConfiguration/SystemConfiguration.h>
20
21
#import <CoreFoundation/CoreFoundation.h>
#import <IOKit/pwr_mgt/IOPMLib.h>
22

Alexandre Lision's avatar
Alexandre Lision committed
23
24
#import "AppDelegate.h"

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
25
//lrc
26
#import <api/lrc.h>
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
27
#import <api/newaccountmodel.h>
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
28
29
30
#import <api/behaviorcontroller.h>
#import <api/conversation.h>
#import <api/newcallmodel.h>
31

32

33
34
35
36
#if ENABLE_SPARKLE
#import <Sparkle/Sparkle.h>
#endif

37
#import "Constants.h"
38
#import "RingWizardWC.h"
Alexandre Lision's avatar
Alexandre Lision committed
39
#import "DialpadWC.h"
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
40
#import "utils.h"
41

42
43
44
#if ENABLE_SPARKLE
@interface AppDelegate() <SUUpdaterDelegate>
#else
45
@interface AppDelegate()
46
#endif
47
48
49

@property RingWindowController* ringWindowController;
@property RingWizardWC* wizard;
Alexandre Lision's avatar
Alexandre Lision committed
50
@property DialpadWC* dialpad;
51
52
@property (nonatomic, strong) dispatch_queue_t scNetworkQueue;
@property (nonatomic, assign) SCNetworkReachabilityRef currentReachability;
53
@property (strong) id activity;
54
55
56

@end

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
57
58
59
60
61
62
63
64
65
66
NSString * const MESSAGE_NOTIFICATION = @"message_notification_type";
NSString * const CALL_NOTIFICATION = @"call_notification_type";
NSString * const CONTACT_REQUEST_NOTIFICATION = @"contact_request_notification_type";

NSString * const ACCOUNT_ID = @"account_id_notification_info";
NSString * const CALL_ID = @"call_id_notification_info";
NSString * const CONVERSATION_ID = @"conversation_id_notification_info";
NSString * const CONTACT_URI = @"contact_uri_notification_info";
NSString * const NOTIFICATION_TYPE = @"contact_type_notification_info";

67
68
IOPMAssertionID assertionID = 0;
BOOL sleepDisabled = false;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
69

70
@implementation AppDelegate {
Alexandre Lision's avatar
Alexandre Lision committed
71

72
73
std::unique_ptr<lrc::api::Lrc> lrc;
}
74

Alexandre Lision's avatar
Alexandre Lision committed
75
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
76
77
78
79
80
81
82
83
84
85
86

    // hide "Check for update" menu item when sparkle is disabled
    NSMenu *mainMenu = [[NSApplication sharedApplication] mainMenu];
    NSMenu *ringMenu = [[mainMenu itemAtIndex:0] submenu];
    NSMenuItem *updateItem = [ringMenu itemAtIndex:1];
#if ENABLE_SPARKLE
    updateItem.hidden = false;
#else
    updateItem.hidden = true;
#endif

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
87
#ifndef NDEBUG
Alexandre Lision's avatar
Alexandre Lision committed
88
    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
89
90
91
#else
    [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints"];
#endif
Alexandre Lision's avatar
Alexandre Lision committed
92

93
94
    [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];

Edric Milaret's avatar
Edric Milaret committed
95
96
    NSAppleEventManager* appleEventManager = [NSAppleEventManager sharedAppleEventManager];
    [appleEventManager setEventHandler:self andSelector:@selector(handleQuitEvent:withReplyEvent:) forEventClass:kCoreEventClass andEventID:kAEQuitApplication];
97
98
99
100
101
102
103

    dispatch_queue_t queue = NULL;
    queue = dispatch_queue_create("scNetworkReachability", DISPATCH_QUEUE_SERIAL);
    [self setScNetworkQueue:queue];
    [self beginObservingReachabilityStatus];
    NSActivityOptions options = NSActivitySuddenTerminationDisabled | NSActivityAutomaticTerminationDisabled | NSActivityBackground;
    self.activity = [[NSProcessInfo processInfo] beginActivityWithOptions:options reason:@"Receiving calls and messages"];
104
    lrc = std::make_unique<lrc::api::Lrc>();
105
    if([self checkForRingAccount]) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
106
        [self setRingtonePath];
107
108
109
110
        [self showMainWindow];
    } else {
        [self showWizard];
    }
111
    [self connect];
112
113
114
115
116
117
118
}

- (void) beginObservingReachabilityStatus
{
    SCNetworkReachabilityRef reachabilityRef = NULL;

    void (^callbackBlock)(SCNetworkReachabilityFlags) = ^(SCNetworkReachabilityFlags flags) {
119
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
120
            lrc->connectivityChanged();
121
        });
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
    };

    SCNetworkReachabilityContext context = {
        .version = 0,
        .info = (void *)CFBridgingRetain(callbackBlock),
        .release = CFRelease
    };

    reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, "test");
    if (SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)){
        if (!SCNetworkReachabilitySetDispatchQueue(reachabilityRef, [self scNetworkQueue]) ){
            // Remove our callback if we can't use the queue
            SCNetworkReachabilitySetCallback(reachabilityRef, NULL, NULL);
        }
        [self setCurrentReachability:reachabilityRef];
    }
}

- (void) endObsvervingReachabilityStatusForHost:(NSString *)__unused host
{
    // Un-set the dispatch queue
    if (SCNetworkReachabilitySetDispatchQueue([self currentReachability], NULL) ){
        SCNetworkReachabilitySetCallback([self currentReachability], NULL, NULL);
    }
}

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
- (void) disableScreenSleep
{
    if (sleepDisabled) {
        return;
    }
    CFStringRef reasonForActivity= CFSTR("Prevent display sleep during calls");
    sleepDisabled = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, reasonForActivity, &assertionID) == kIOReturnSuccess;
}

- (void) restoreScreenSleep {
    auto calls = [self getActiveCalls];

    if (!sleepDisabled || !calls.empty()) {
        return;
    }
    IOPMAssertionRelease(assertionID);
    sleepDisabled = false;
}

167
168
169
170
static void ReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkConnectionFlags flags, void* info)
{
    void (^callbackBlock)(SCNetworkReachabilityFlags) = (__bridge id)info;
    callbackBlock(flags);
171
172
173
174
}

- (void) connect
{
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
175
176
    QObject::connect(&lrc->getBehaviorController(),
                     &lrc::api::BehaviorController::newTrustRequest,
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
177
                     [self] (const QString& accountId, const QString& contactUri) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
        BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:Preferences::ContactRequestNotifications];
        if(!shouldNotify) {
            return;
        }
        NSUserNotification* notification = [[NSUserNotification alloc] init];
        auto contactModel = lrc->getAccountModel()
        .getAccountInfo(accountId).contactModel.get();
        NSString* name = contactModel->getContact(contactUri)
        .registeredName.isEmpty() ?
        contactUri.toNSString():
        contactModel->getContact(contactUri).registeredName.toNSString();
        NSString* localizedMessage =
        NSLocalizedString(@"Send you a contact request",
                          @"Notification message");

        NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
        userInfo[ACCOUNT_ID] = accountId.toNSString();
        userInfo[CONTACT_URI] = contactUri.toNSString();
        userInfo[NOTIFICATION_TYPE] = CONTACT_REQUEST_NOTIFICATION;

        [notification setTitle: name];
        notification.informativeText = localizedMessage;
        [notification setSoundName:NSUserNotificationDefaultSoundName];
        [notification setUserInfo: userInfo];

        [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];

    });
206

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
207
208
    QObject::connect(&lrc->getBehaviorController(),
                     &lrc::api::BehaviorController::showIncomingCallView,
209
210
                     [self] (const QString& accountId,
                             const QString& convUid) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
211
212
213
214
        BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:Preferences::CallNotifications];
        if(!shouldNotify) {
            return;
        }
215
216
217
        auto convModel = lrc->getAccountModel().getAccountInfo(accountId).conversationModel.get();
        auto conversationOpt = getConversationFromUid(convUid, *convModel);
        if (!conversationOpt.has_value()) { return; }
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
218
        lrc::api::conversation::Info& conversation = *conversationOpt;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
219
        bool isIncoming = false;
220
221
222
        auto callModel = lrc->getAccountModel().getAccountInfo(accountId).callModel.get();
        if(callModel->hasCall(conversation.callId)) {
            isIncoming = !callModel->getCall(conversation.callId).isOutgoing;
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
223
224
225
226
        }
        if(!isIncoming) {
            return;
        }
227
        NSString* name = bestIDForConversation(conversation, *lrc->getAccountModel().getAccountInfo(accountId).conversationModel.get());
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
228
229
230
231
        NSUserNotification* notification = [[NSUserNotification alloc] init];

        NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
        userInfo[ACCOUNT_ID] = accountId.toNSString();
232
233
        userInfo[CALL_ID] = conversation.callId.toNSString();
        userInfo[CONVERSATION_ID] = conversation.uid.toNSString();
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
        userInfo[NOTIFICATION_TYPE] = CALL_NOTIFICATION;

        NSString* localizedTitle = [NSString stringWithFormat:
                                    NSLocalizedString(@"Incoming call from %@", @"Incoming call from {Name}"),
                                    name];
        // try to activate action button
        @try {
            [notification setValue:@YES forKey:@"_showsButtons"];
        }
        @catch (NSException *exception) {
            NSLog(@"Action button not activable on notification");
        }
        [notification setUserInfo: userInfo];
        [notification setOtherButtonTitle:NSLocalizedString(@"Refuse", @"Button Action")];
        [notification setActionButtonTitle:NSLocalizedString(@"Accept", @"Button Action")];
        [notification setTitle:localizedTitle];
        [notification setSoundName:NSUserNotificationDefaultSoundName];

        [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
    });
254

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
255
256
    QObject::connect(&lrc->getBehaviorController(),
                     &lrc::api::BehaviorController::newUnreadInteraction,
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
257
                     [self] (const QString& accountId, const QString& conversation,
258
                             const QString& interactionId, const lrc::api::interaction::Info& interaction) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
259
260
261
262
263
264
265
266
267
268
269
        BOOL shouldNotify = [[NSUserDefaults standardUserDefaults] boolForKey:Preferences::MessagesNotifications];
        if(!shouldNotify) {
            return;
        }
        NSUserNotification* notification = [[NSUserNotification alloc] init];

        NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
        userInfo[ACCOUNT_ID] = accountId.toNSString();
        userInfo[CONVERSATION_ID] = conversation.toNSString();
        userInfo[NOTIFICATION_TYPE] = MESSAGE_NOTIFICATION;
        NSString* name = interaction.authorUri.toNSString();
270
        auto convOpt = getConversationFromUid(conversation, *lrc->getAccountModel()
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
271
                                             .getAccountInfo(accountId)
272
                                             .conversationModel.get());
273
        if (convOpt.has_value()) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
274
            lrc::api::conversation::Info& conversation = *convOpt;
275
            name = bestIDForConversation(conversation, *lrc->getAccountModel().getAccountInfo(accountId).conversationModel.get());
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
276
277
278
279
280
281
282
283
284
285
286
287
        }
        NSString* localizedTitle = [NSString stringWithFormat:
                                    NSLocalizedString(@"Incoming message from %@",@"Incoming message from {Name}"),
                                    name];

        [notification setTitle:localizedTitle];
        [notification setSoundName:NSUserNotificationDefaultSoundName];
        [notification setSubtitle:interaction.body.toNSString()];
        [notification setUserInfo:userInfo];

        [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
    });
288
289
}

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
290
291
292
293
294
- (void)userNotificationCenter:(NSUserNotificationCenter *)center didDismissAlert:(NSUserNotification *)alert {
    // check if user click refuse on incoming call notifications
    if(alert.activationType != NSUserNotificationActivationTypeNone) {
        return;
    }
295

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
296
297
298
    auto info = alert.userInfo;
    if(!info) {
        return;
Alexandre Lision's avatar
Alexandre Lision committed
299
    }
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
300
301
302
303
304
305
306
307
308
309
310
311
    NSString* identifier = info[NOTIFICATION_TYPE];
    NSString* callId = info[CALL_ID];
    NSString* accountId = info[ACCOUNT_ID];
    if(!identifier || !callId || !accountId) {
        return;
    }
    if([identifier isEqualToString: CALL_NOTIFICATION]) {
        auto accountInfo = &lrc->getAccountModel().getAccountInfo([accountId UTF8String]);
        if (accountInfo == nil)
            return;
        auto* callModel = accountInfo->callModel.get();
        callModel->hangUp([callId UTF8String]);
Alexandre Lision's avatar
Alexandre Lision committed
312
    }
Alexandre Lision's avatar
Alexandre Lision committed
313
314
}

Alexandre Lision's avatar
Alexandre Lision committed
315
316
- (void) userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification
{
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
    auto info = notification.userInfo;
    if(!info) {
        return;
    }
    NSString* identifier = info[NOTIFICATION_TYPE];
    if([identifier isEqualToString: CALL_NOTIFICATION]) {
        if(notification.activationType == NSUserNotificationActivationTypeActionButtonClicked
           || notification.activationType == NSUserNotificationActivationTypeContentsClicked) {
            NSString* callId = info[CALL_ID];
            NSString* accountId = info[ACCOUNT_ID];
            NSString *conversationId = info[CONVERSATION_ID];
            auto accountInfo = &lrc->getAccountModel().getAccountInfo([accountId UTF8String]);
            if (accountInfo == nil)
                return;
            auto* callModel = accountInfo->callModel.get();
            callModel->accept([callId UTF8String]);
Alexandre Lision's avatar
Alexandre Lision committed
333
            [self.ringWindowController.window deminiaturize:self];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
334
335
336
337
338
339
340
341
342
343
344
345
            [_ringWindowController showCall:callId forAccount:accountId forConversation:conversationId];
        }
    } else if(notification.activationType == NSUserNotificationActivationTypeContentsClicked) {
        [self.ringWindowController.window deminiaturize:self];
        if([identifier isEqualToString: MESSAGE_NOTIFICATION]) {
            NSString* accountId = info[ACCOUNT_ID];
            NSString *conversationId = info[CONVERSATION_ID];
            [_ringWindowController showConversation:conversationId forAccount:accountId];
        } else if([identifier isEqualToString: CONTACT_REQUEST_NOTIFICATION]) {
            NSString* accountId = info[ACCOUNT_ID];
            NSString *contactUri = info[CONTACT_URI];
            [_ringWindowController showContactRequestFor:accountId contactUri: contactUri];
Alexandre Lision's avatar
Alexandre Lision committed
346
347
        }
    }
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
348
    [[NSUserNotificationCenter defaultUserNotificationCenter] removeAllDeliveredNotifications];
Alexandre Lision's avatar
Alexandre Lision committed
349
350
}

351
352
353
- (void) showWizard
{
    if(self.wizard == nil) {
354
        self.wizard = [[RingWizardWC alloc] initWithNibName:@"RingWizard" bundle: nil accountmodel: &lrc->getAccountModel()];
355
    }
356
    [self.wizard.window makeKeyAndOrderFront:self];
357
358
359
360
}

- (void) showMainWindow
{
361
    if(self.ringWindowController == nil) {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
362
        self.ringWindowController = [[RingWindowController alloc] initWithWindowNibName:@"RingWindow" bundle: nil accountModel:&lrc->getAccountModel()  behaviourController:&lrc->getBehaviorController() avModel: &lrc->getAVModel() pluginModel: &lrc->getPluginModel()];
363
    }
364
    [[NSApplication sharedApplication] removeWindowsItem:self.wizard.window];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
365
    self.wizard = nil;
366
367
368
    [self.ringWindowController.window makeKeyAndOrderFront:self];
}

Alexandre Lision's avatar
Alexandre Lision committed
369
370
371
372
373
374
375
376
- (void) showDialpad
{
    if (self.dialpad == nil) {
        self.dialpad = [[DialpadWC alloc] initWithWindowNibName:@"Dialpad"];
    }
    [self.dialpad.window makeKeyAndOrderFront:self];
}

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
377
-(QVector<QString>) getActiveCalls {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
378
379
    return lrc->activeCalls();
}
Alexandre Lision's avatar
Alexandre Lision committed
380

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
381
382
383
384
-(QVector<QString>)getConferenceSubcalls:(QString)confId {
    return lrc->getConferenceSubcalls(confId);
}

Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
385
-(void)setRingtonePath {
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
386
    QStringList accounts = lrc->getAccountModel().getAccountList();
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
387
388
389
    NSFileManager *fileManager = [NSFileManager defaultManager];
    for (auto account: accounts) {
        lrc::api::account::ConfProperties_t accountProperties = lrc->getAccountModel().getAccountConfig(account);
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
390
        NSString *ringtonePath = accountProperties.Ringtone.ringtonePath.toNSString();
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
391
392
393
394
395
396
397
        if (![fileManager fileExistsAtPath: ringtonePath]) {
            accountProperties.Ringtone.ringtonePath = [defaultRingtonePath() UTF8String];
            lrc->getAccountModel().setAccountConfig(account, accountProperties);
        }
    }
}

398
399
- (BOOL) checkForRingAccount
{
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
400
    return !lrc->getAccountModel().getAccountList().empty();
401
402
}

403
404
405
406
407
408
409
410
-(void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
    NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
    [appleEventManager setEventHandler:self
                           andSelector:@selector(handleGetURLEvent:withReplyEvent:)
                         forEventClass:kInternetEventClass andEventID:kAEGetURL];
}

411
412
413
414
415
416
417
418
419
420
- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
{
    if([self checkForRingAccount]) {
        [self showMainWindow];
    } else {
        [self showWizard];
    }
    return YES;
}

Edric Milaret's avatar
Edric Milaret committed
421
422
- (void)handleQuitEvent:(NSAppleEventDescriptor*)event withReplyEvent:(NSAppleEventDescriptor*)replyEvent
{
423
    [[NSApplication sharedApplication] terminate:self];
Edric Milaret's avatar
Edric Milaret committed
424
425
426
427
}

-(void)applicationWillTerminate:(NSNotification *)notification
{
428
429
430
431
432
    [self cleanExit];
}

- (void) cleanExit
{
433
434
435
    if (self.activity != nil) {
        [[NSProcessInfo processInfo] endActivity:self.activity];
        self.activity = nil;
436
    }
437
438
    [self.wizard close];
    [self.ringWindowController close];
Kateryna Kostiuk's avatar
Kateryna Kostiuk committed
439
    lrc.reset();
Edric Milaret's avatar
Edric Milaret committed
440
441
}

442
443
#if ENABLE_SPARKLE

444
#pragma mark - Sparkle delegate
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466

- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update
{
    [NSApp activateIgnoringOtherApps:YES];
}

- (BOOL)updaterMayCheckForUpdates:(SUUpdater *)bundle
{
    return YES;
}

- (BOOL)updaterShouldRelaunchApplication:(SUUpdater *)updater
{
    return YES;
}

- (void)updater:(SUUpdater *)updater didAbortWithError:(NSError *)error
{
    NSLog(@"Error:%@", error.localizedDescription);
}

#endif
Alexandre Lision's avatar
Alexandre Lision committed
467
@end