зеркало из https://github.com/nextcloud/talk-ios.git
314 строки
14 KiB
Objective-C
314 строки
14 KiB
Objective-C
//
|
|
// NCNotificationController.m
|
|
// VideoCalls
|
|
//
|
|
// Created by Ivan Sein on 23.10.18.
|
|
// Copyright © 2018 struktur AG. All rights reserved.
|
|
//
|
|
|
|
#import "NCNotificationController.h"
|
|
#import <UserNotifications/UserNotifications.h>
|
|
|
|
#import "NCAPIController.h"
|
|
#import "NCConnectionController.h"
|
|
#import "NCNotification.h"
|
|
#import "NCRoomsManager.h"
|
|
#import "NCSettingsController.h"
|
|
#import "NCUserInterfaceController.h"
|
|
#import "CallKitManager.h"
|
|
|
|
NSString * const NCNotificationControllerWillPresentNotification = @"NCNotificationControllerWillPresentNotification";
|
|
NSString * const NCLocalNotificationJoinChatNotification = @"NCLocalNotificationJoinChatNotification";
|
|
|
|
@interface NCNotificationController () <UNUserNotificationCenterDelegate>
|
|
|
|
@property (nonatomic, strong) UNUserNotificationCenter *notificationCenter;
|
|
@property (nonatomic, strong) NSMutableDictionary *serverNotificationsAttempts; // notificationId -> get attempts
|
|
|
|
@end
|
|
|
|
@implementation NCNotificationController
|
|
|
|
+ (NCNotificationController *)sharedInstance
|
|
{
|
|
static dispatch_once_t once;
|
|
static NCNotificationController *sharedInstance;
|
|
dispatch_once(&once, ^{
|
|
sharedInstance = [[self alloc] init];
|
|
});
|
|
return sharedInstance;
|
|
}
|
|
|
|
- (id)init
|
|
{
|
|
self = [super init];
|
|
if (self) {
|
|
_notificationCenter = [UNUserNotificationCenter currentNotificationCenter];
|
|
_notificationCenter.delegate = self;
|
|
_serverNotificationsAttempts = [[NSMutableDictionary alloc] init];
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)requestAuthorization
|
|
{
|
|
UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
|
|
[_notificationCenter requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) {
|
|
if (granted) {
|
|
NSLog(@"User notifications permission granted.");
|
|
} else {
|
|
NSLog(@"User notifications permission denied.");
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)processIncomingPushNotification:(NCPushNotification *)pushNotification
|
|
{
|
|
if (pushNotification) {
|
|
NSInteger notificationId = pushNotification.notificationId;
|
|
if (pushNotification.type == NCPushNotificationTypeDelete) {
|
|
[self removeNotificationWithNotificationId:notificationId];
|
|
} else if (pushNotification.type == NCPushNotificationTypeDeleteAll) {
|
|
[self cleanAllNotifications];
|
|
} else {
|
|
[self handlePushNotification:pushNotification];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)showLocalNotificationForPushNotification:(NCPushNotification *)pushNotification withServerNotification:(NCNotification *)serverNotification
|
|
{
|
|
UNMutableNotificationContent *content = [UNMutableNotificationContent new];
|
|
content.body = pushNotification.bodyForRemoteAlerts;
|
|
content.threadIdentifier = pushNotification.roomToken;
|
|
content.sound = [UNNotificationSound defaultSound];
|
|
NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] init];
|
|
[userInfo setObject:pushNotification.jsonString forKey:@"pushNotification"];
|
|
[userInfo setObject:pushNotification.accountId forKey:@"accountId"];
|
|
content.userInfo = userInfo;
|
|
|
|
if (serverNotification) {
|
|
content.threadIdentifier = serverNotification.objectId;
|
|
if (serverNotification.notificationType == kNCNotificationTypeChat) {
|
|
content.title = serverNotification.chatMessageTitle;
|
|
content.body = serverNotification.message;
|
|
if (@available(iOS 12.0, *)) {
|
|
content.summaryArgument = serverNotification.chatMessageAuthor;
|
|
}
|
|
}
|
|
}
|
|
|
|
NSString *identifier = [NSString stringWithFormat:@"Notification-%ld", (long)pushNotification.notificationId];
|
|
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.1 repeats:NO];
|
|
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
|
|
[_notificationCenter addNotificationRequest:request withCompletionHandler:nil];
|
|
|
|
[self updateAppIconBadgeNumber:1];
|
|
|
|
NSString *activeAccountId = [[[NCDatabaseManager sharedInstance] activeAccount] accountId];
|
|
if (![activeAccountId isEqualToString:pushNotification.accountId]) {
|
|
[[NCDatabaseManager sharedInstance] increaseUnreadBadgeNumberForAccountId:pushNotification.accountId];
|
|
}
|
|
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCNotificationControllerWillPresentNotification object:self userInfo:nil];
|
|
}
|
|
|
|
- (void)handlePushNotification:(NCPushNotification *)pushNotification
|
|
{
|
|
NSInteger notificationId = pushNotification.notificationId;
|
|
NSInteger retryAttempts = [[_serverNotificationsAttempts objectForKey:@(notificationId)] integerValue];
|
|
if (retryAttempts < 3 && notificationId) {
|
|
retryAttempts += 1;
|
|
[_serverNotificationsAttempts setObject:@(retryAttempts) forKey:@(notificationId)];
|
|
TalkAccount *talkAccount = [[NCDatabaseManager sharedInstance] talkAccountForAccountId:pushNotification.accountId];
|
|
[[NCAPIController sharedInstance] getServerNotification:notificationId forAccount:talkAccount withCompletionBlock:^(NSDictionary *notification, NSError *error, NSInteger statusCode) {
|
|
if (statusCode == 404) {
|
|
// Notification has been treated/deleted in another device
|
|
return;
|
|
}
|
|
if (!error) {
|
|
NCNotification *serverNotification = [NCNotification notificationWithDictionary:notification];
|
|
if (serverNotification) {
|
|
if (serverNotification.notificationType == kNCNotificationTypeChat) {
|
|
[self showLocalNotificationForPushNotification:pushNotification withServerNotification:serverNotification];
|
|
} else if (serverNotification.notificationType == kNCNotificationTypeCall) {
|
|
NSString *callType = [[serverNotification.subjectRichParameters objectForKey:@"call"] objectForKey:@"call-type"];
|
|
if ([CallKitManager isCallKitAvailable] && ![[CallKitManager sharedInstance] currentCallUUID] && [callType isEqualToString:@"one2one"]) {
|
|
[self showIncomingCallForPushNotification:pushNotification withServerNotification:serverNotification];
|
|
} else {
|
|
[self showLocalNotificationForPushNotification:pushNotification withServerNotification:serverNotification];
|
|
}
|
|
} else if (serverNotification.notificationType == kNCNotificationTypeRoom) {
|
|
NSString *callType = [[serverNotification.subjectRichParameters objectForKey:@"call"] objectForKey:@"call-type"];
|
|
// Only present invitation notifications for group conversations
|
|
if (![callType isEqualToString:@"one2one"]) {
|
|
[self showLocalNotificationForPushNotification:pushNotification withServerNotification:serverNotification];
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
NSLog(@"Could not retrieve server notification. Attempt:%ld", (long)retryAttempts);
|
|
[self handlePushNotification:pushNotification];
|
|
}
|
|
}];
|
|
} else {
|
|
[self showLocalNotificationForPushNotification:pushNotification withServerNotification:nil];
|
|
}
|
|
}
|
|
|
|
- (void)showLocalNotification:(NCLocalNotificationType)type withUserInfo:(NSDictionary *)userInfo
|
|
{
|
|
UNMutableNotificationContent *content = [UNMutableNotificationContent new];
|
|
|
|
switch (type) {
|
|
case kNCLocalNotificationTypeMissedCall:
|
|
{
|
|
content.body = [NSString stringWithFormat:@"☎️ Missed call from %@", [userInfo objectForKey:@"displayName"]];
|
|
content.userInfo = userInfo;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
NSString *identifier = [NSString stringWithFormat:@"Notification-%f", [[NSDate date] timeIntervalSince1970]];
|
|
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.1 repeats:NO];
|
|
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
|
|
[_notificationCenter addNotificationRequest:request withCompletionHandler:nil];
|
|
[[NSNotificationCenter defaultCenter] postNotificationName:NCNotificationControllerWillPresentNotification object:self userInfo:nil];
|
|
|
|
[self updateAppIconBadgeNumber:1];
|
|
}
|
|
|
|
- (void)showIncomingCallForPushNotification:(NCPushNotification *)pushNotification withServerNotification:(NCNotification *)serverNotification
|
|
{
|
|
NSString *roomToken = serverNotification.objectId;
|
|
NSString *displayName = serverNotification.callDisplayName;
|
|
// Set active account
|
|
[[NCSettingsController sharedInstance] setActiveAccountWithAccountId:pushNotification.accountId];
|
|
// Present call
|
|
[[CallKitManager sharedInstance] reportIncomingCallForRoom:roomToken withDisplayName:displayName forAccountId:pushNotification.accountId];
|
|
}
|
|
|
|
- (void)updateAppIconBadgeNumber:(NSInteger)update
|
|
{
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
|
|
[UIApplication sharedApplication].applicationIconBadgeNumber += update;
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void)cleanAllNotifications
|
|
{
|
|
[_notificationCenter removeAllDeliveredNotifications];
|
|
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
|
|
}
|
|
|
|
- (void)removeNotificationWithNotificationId:(NSInteger)notificationId
|
|
{
|
|
NSString *identifier = [NSString stringWithFormat:@"Notification-%ld", (long)notificationId];
|
|
// Check in pending notifications
|
|
[_notificationCenter getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
|
|
for (UNNotificationRequest *notificationRequest in requests) {
|
|
if ([notificationRequest.identifier isEqualToString:identifier]) {
|
|
[_notificationCenter removePendingNotificationRequestsWithIdentifiers:@[identifier]];
|
|
[self updateAppIconBadgeNumber:-1];
|
|
}
|
|
}
|
|
}];
|
|
// Check in delivered notifications
|
|
[_notificationCenter getDeliveredNotificationsWithCompletionHandler:^(NSArray<UNNotification *> * _Nonnull notifications) {
|
|
for (UNNotification *notification in notifications) {
|
|
if ([notification.request.identifier isEqualToString:identifier]) {
|
|
[_notificationCenter removeDeliveredNotificationsWithIdentifiers:@[identifier]];
|
|
[self updateAppIconBadgeNumber:-1];
|
|
}
|
|
}
|
|
}];
|
|
}
|
|
|
|
#pragma mark - UNUserNotificationCenter delegate
|
|
|
|
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
|
|
{
|
|
//Called when a notification is delivered to a foreground app.
|
|
completionHandler(UNNotificationPresentationOptionAlert);
|
|
}
|
|
|
|
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
|
|
{
|
|
if ([NCRoomsManager sharedInstance].callViewController) {
|
|
completionHandler();
|
|
return;
|
|
}
|
|
|
|
UNNotificationRequest *notificationRequest = response.notification.request;
|
|
NCLocalNotificationType localNotificationType = (NCLocalNotificationType)[[notificationRequest.content.userInfo objectForKey:@"localNotificationType"] integerValue];
|
|
NSString *notificationString = [notificationRequest.content.userInfo objectForKey:@"pushNotification"];
|
|
NSString *notificationAccountId = [notificationRequest.content.userInfo objectForKey:@"accountId"];
|
|
NCPushNotification *pushNotification = [NCPushNotification pushNotificationFromDecryptedString:notificationString withAccountId:notificationAccountId];
|
|
|
|
// Change account if notification is from another account
|
|
if (notificationAccountId && ![[[NCDatabaseManager sharedInstance] activeAccount].accountId isEqualToString:notificationAccountId]) {
|
|
// Leave chat before changing accounts
|
|
if ([[NCRoomsManager sharedInstance] chatViewController]) {
|
|
[[[NCRoomsManager sharedInstance] chatViewController] leaveChat];
|
|
}
|
|
// Set notification account active
|
|
[[NCSettingsController sharedInstance] setActiveAccountWithAccountId:notificationAccountId];
|
|
}
|
|
|
|
// Handle notification response
|
|
if (pushNotification) {
|
|
[self handlePushNotificationResponse:pushNotification withCompletionHandler:completionHandler];
|
|
} else if (localNotificationType > 0) {
|
|
[self handleLocalNotificationResponse:notificationRequest.content.userInfo withCompletionHandler:completionHandler];
|
|
}
|
|
}
|
|
|
|
- (void)handlePushNotificationResponse:(NCPushNotification *)pushNotification withCompletionHandler:(void (^)(void))completionHandler
|
|
{
|
|
if (pushNotification) {
|
|
switch (pushNotification.type) {
|
|
case NCPushNotificationTypeCall:
|
|
{
|
|
[[NCUserInterfaceController sharedInstance] presentAlertForPushNotification:pushNotification];
|
|
}
|
|
break;
|
|
case NCPushNotificationTypeRoom:
|
|
case NCPushNotificationTypeChat:
|
|
{
|
|
[[NCUserInterfaceController sharedInstance] presentChatForPushNotification:pushNotification];
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
completionHandler();
|
|
}
|
|
|
|
- (void)handleLocalNotificationResponse:(NSDictionary *)notificationUserInfo withCompletionHandler:(void (^)(void))completionHandler
|
|
{
|
|
NCLocalNotificationType localNotificationType = (NCLocalNotificationType)[[notificationUserInfo objectForKey:@"localNotificationType"] integerValue];
|
|
if (localNotificationType > 0) {
|
|
switch (localNotificationType) {
|
|
case kNCLocalNotificationTypeMissedCall:
|
|
{
|
|
[[NCUserInterfaceController sharedInstance] presentChatForLocalNotification:notificationUserInfo];
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
completionHandler();
|
|
}
|
|
|
|
@end
|