Commit 40533583 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk Committed by Andreas Traczyk

notifications: add local notifications

Present local notifications when receiving incoming calls or
messages.

Change-Id: Ib650474c466678778bed26b564485316ed964a2f
Reviewed-by: Andreas Traczyk's avatarAndreas Traczyk <andreas.traczyk@savoirfairelinux.com>
parent 70ec95af
......@@ -104,6 +104,7 @@
0E2D5F551F9145F200D574BF /* LinkNewDeviceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E2D5F541F9145F200D574BF /* LinkNewDeviceCell.xib */; };
0E403F811F7D797300C80BC2 /* MessageCellGenerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */; };
0E403F831F7D79B000C80BC2 /* MessageCellGenerated.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */; };
0E44B62F202B9DE40060F71B /* LocalNotificationsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E44B62E202B9DE40060F71B /* LocalNotificationsHelper.swift */; };
0E48F9D31FDF150700D6CC08 /* ContactRequestManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E48F9D21FDF150700D6CC08 /* ContactRequestManager.swift */; };
0E4909611FE97A94005CAA50 /* ActiveLabel.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E4909601FE97A94005CAA50 /* ActiveLabel.framework */; };
0E49096A1FEAB156005CAA50 /* CallsAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0E4909691FEAB156005CAA50 /* CallsAdapter.mm */; };
......@@ -126,6 +127,7 @@
0EB1A5CF1F8EBE03009923E2 /* DeviceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0EB1A5CE1F8EBE03009923E2 /* DeviceCell.xib */; };
0EB1A5D11F8EBE23009923E2 /* DeviceCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB1A5D01F8EBE23009923E2 /* DeviceCell.swift */; };
0EB479951FA28A7300106AFD /* ButtonTransparentBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EB479941FA28A7300106AFD /* ButtonTransparentBackground.swift */; };
0EBCAA4E202E60F000E2A545 /* default.wav in Resources */ = {isa = PBXBuildFile; fileRef = 0EBCAA4D202E60F000E2A545 /* default.wav */; };
0ED2B6FA1F96A075001572F0 /* LinkNewDeviceViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0ED2B6F91F96A075001572F0 /* LinkNewDeviceViewController.storyboard */; };
0ED2B6FC1F96A158001572F0 /* LinkNewDeviceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED2B6FB1F96A158001572F0 /* LinkNewDeviceViewController.swift */; };
0ED2B6FE1F96A16C001572F0 /* LinkNewDeviceViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ED2B6FD1F96A16C001572F0 /* LinkNewDeviceViewModel.swift */; };
......@@ -372,6 +374,7 @@
0E2D5F541F9145F200D574BF /* LinkNewDeviceCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LinkNewDeviceCell.xib; sourceTree = "<group>"; };
0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCellGenerated.swift; sourceTree = "<group>"; };
0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessageCellGenerated.xib; sourceTree = "<group>"; };
0E44B62E202B9DE40060F71B /* LocalNotificationsHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNotificationsHelper.swift; sourceTree = "<group>"; };
0E48F9D21FDF150700D6CC08 /* ContactRequestManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestManager.swift; sourceTree = "<group>"; };
0E4909601FE97A94005CAA50 /* ActiveLabel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ActiveLabel.framework; path = Carthage/Build/iOS/ActiveLabel.framework; sourceTree = "<group>"; };
0E4909681FEAB156005CAA50 /* CallsAdapter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CallsAdapter.h; sourceTree = "<group>"; };
......@@ -396,6 +399,7 @@
0EB1A5CE1F8EBE03009923E2 /* DeviceCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DeviceCell.xib; sourceTree = "<group>"; };
0EB1A5D01F8EBE23009923E2 /* DeviceCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceCell.swift; sourceTree = "<group>"; };
0EB479941FA28A7300106AFD /* ButtonTransparentBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonTransparentBackground.swift; sourceTree = "<group>"; };
0EBCAA4D202E60F000E2A545 /* default.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = default.wav; sourceTree = "<group>"; };
0ED2B6F91F96A075001572F0 /* LinkNewDeviceViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LinkNewDeviceViewController.storyboard; sourceTree = "<group>"; };
0ED2B6FB1F96A158001572F0 /* LinkNewDeviceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceViewController.swift; sourceTree = "<group>"; };
0ED2B6FD1F96A16C001572F0 /* LinkNewDeviceViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkNewDeviceViewModel.swift; sourceTree = "<group>"; };
......@@ -852,6 +856,7 @@
043999F51D1C2D9D00E99CD9 /* Ring */ = {
isa = PBXGroup;
children = (
0E44B62D202B9DC40060F71B /* Helpers */,
0E63F1F3202907090001F248 /* Ring.entitlements */,
0E0FF1A81FC38409003898C2 /* Database */,
02E1A0261DDE4C2E00D75B59 /* Services */,
......@@ -983,6 +988,14 @@
path = DBHelpers;
sourceTree = "<group>";
};
0E44B62D202B9DC40060F71B /* Helpers */ = {
isa = PBXGroup;
children = (
0E44B62E202B9DE40060F71B /* LocalNotificationsHelper.swift */,
);
path = Helpers;
sourceTree = "<group>";
};
0E4909711FEAC822005CAA50 /* Calls */ = {
isa = PBXGroup;
children = (
......@@ -1290,6 +1303,7 @@
1ABE07C61F0D86B300D36361 /* Resources */ = {
isa = PBXGroup;
children = (
0EBCAA4D202E60F000E2A545 /* default.wav */,
1ABE07DA1F0D915100D36361 /* Localizable.strings */,
04399A021D1C2D9D00E99CD9 /* Images.xcassets */,
);
......@@ -1522,6 +1536,7 @@
files = (
1A2D18FD1F292DAD00B2C785 /* ConversationCell.xib in Resources */,
1ABE07DC1F0D915100D36361 /* Localizable.strings in Resources */,
0EBCAA4E202E60F000E2A545 /* default.wav in Resources */,
1A2D18E61F29197100B2C785 /* MessageAccessoryView.xib in Resources */,
1A2D18F81F292D7200B2C785 /* MessageCellSent.xib in Resources */,
1A2D18F61F292D7200B2C785 /* MessageCellReceived.xib in Resources */,
......@@ -1715,6 +1730,7 @@
621231FB1F8D6FEE009B86F0 /* MessageCell.swift in Sources */,
56AC650E1E85694D00EA1AA9 /* DesignableTextField.swift in Sources */,
1A2D189A1F2642C000B2C785 /* NotificationCenter+Ring.swift in Sources */,
0E44B62F202B9DE40060F71B /* LocalNotificationsHelper.swift in Sources */,
1A2D18FC1F292DAD00B2C785 /* ConversationCell.swift in Sources */,
0E48F9D31FDF150700D6CC08 /* ContactRequestManager.swift in Sources */,
0E7CF4DD20165BFB00CD967D /* ButtonsContainerViewModel.swift in Sources */,
......
......@@ -28,7 +28,7 @@ import Contacts
import PushKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
var window: UIWindow?
private let daemonService = DaemonService(dRingAdaptor: DRingAdapter())
private let accountService = AccountsService(withAccountAdapter: AccountAdapter())
......@@ -70,7 +70,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
self.window = UIWindow(frame: UIScreen.main.bounds)
UserDefaults.standard.setValue(false, forKey: "_UIConstraintBasedLayoutLogUnsatisfiable")
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self
}
// initialize log format
let console = ConsoleDestination()
console.format = "$Dyyyy-MM-dd HH:mm:ss.SSS$d $C$L$c: $M"
......@@ -101,7 +103,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// load accounts during splashscreen
// and ask the AppCoordinator to handle the first screen once loading is finished
self.conversationManager = ConversationsManager(with: self.conversationsService, accountsService: self.accountService)
self.conversationManager = ConversationsManager(with: self.conversationsService, accountsService: self.accountService, nameService: self.nameService)
self.startDB()
self.accountService.loadAccounts().subscribe { [unowned self] (_) in
guard let currentAccount = self.accountService.currentAccount else {
......@@ -134,6 +136,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
NotificationCenter.default.addObserver(self, selector: #selector(unregisterVoipNotifications),
name: NSNotification.Name(rawValue: NotificationName.disablePushNotifications.rawValue),
object: nil)
self.clearBadgeNumber()
return true
}
......@@ -150,6 +153,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
self.stopDaemon()
}
func applicationDidBecomeActive(_ application: UIApplication) {
self.clearBadgeNumber()
}
// MARK: - Ring Daemon
fileprivate func startDaemon() {
......@@ -200,7 +207,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
self.accountService.setPushNotificationToken(token: "")
}
func requestNotificationAuthorization() {
private func requestNotificationAuthorization() {
let application = UIApplication.shared
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = application.delegate as? UNUserNotificationCenterDelegate
......@@ -211,6 +218,50 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
application.registerUserNotificationSettings(settings)
}
}
private func clearBadgeNumber() {
UIApplication.shared.applicationIconBadgeNumber = 0
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()
center.removeAllDeliveredNotifications()
center.removeAllPendingNotificationRequests()
} else {
UIApplication.shared.cancelAllLocalNotifications()
}
}
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let data = response.notification.request.content.userInfo
self.handleNotificationActions(data: data, responseIdentifier: response.actionIdentifier)
completionHandler()
}
func handleNotificationActions(data: [AnyHashable: Any], responseIdentifier: String) {
guard let callID = data[NotificationUserInfoKeys.callID.rawValue] as? String else {
return
}
switch responseIdentifier {
case CallAcition.accept.rawValue:
NotificationCenter.default.post(name: NSNotification.Name(NotificationName.answerCallFromNotifications.rawValue),
object: nil,
userInfo: data)
case CallAcition.refuse.rawValue:
self.callService.refuse(callId: callID)
.subscribe({_ in
print("Call ignored")
}).disposed(by: self.disposeBag)
default:
print("Other Action")
}
}
func application(_ application: UIApplication, handleActionWithIdentifier identifier: String?, for notification: UILocalNotification, completionHandler: @escaping () -> Void) {
if let identifier = identifier, let data = notification.userInfo {
self.handleNotificationActions(data: data, responseIdentifier: identifier)
}
completionHandler()
}
}
extension AppDelegate: PKPushRegistryDelegate {
......
......@@ -65,6 +65,15 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, CallMakeable {
}).disposed(by: self.disposeBag)
self.navigationViewController.viewModel = ChatTabBarItemViewModel(with: self.injectionBag)
self.callbackPlaceCall()
NotificationCenter.default.addObserver(self, selector: #selector(self.incomingCall(_:)), name: NSNotification.Name(NotificationName.answerCallFromNotifications.rawValue), object: nil)
}
@objc func incomingCall(_ notification: NSNotification) {
guard let callid = notification.userInfo?[NotificationUserInfoKeys.callID.rawValue] as? String,
let call = self.callService.call(callID: callid) else {
return
}
self.answerIncomingCall(call: call)
}
func start () {
......@@ -78,7 +87,7 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, CallMakeable {
self.present(viewController: conversationViewController, withStyle: .show, withAnimation: true, withStateable: conversationViewController.viewModel)
}
private func answerIncomingCall(call: CallModel) {
func answerIncomingCall(call: CallModel) {
let callViewController = CallViewController.instantiate(with: self.injectionBag)
callViewController.viewModel.call = call
callViewController.viewModel.answerCall()
......@@ -88,19 +97,27 @@ class ConversationsCoordinator: Coordinator, StateableResponsive, CallMakeable {
}
private func showCallAlert(call: CallModel) {
let alertStyle = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad) ? UIAlertControllerStyle.alert : UIAlertControllerStyle.actionSheet
let alert = UIAlertController(title: L10n.Alerts.incomingCallAllertTitle + "\(call.displayName)", message: nil, preferredStyle: alertStyle)
alert.addAction(UIAlertAction(title: L10n.Alerts.incomingCallButtonAccept, style: UIAlertActionStyle.default, handler: { (_) in
self.answerIncomingCall(call: call)
alert.dismiss(animated: true, completion: nil)}))
alert.addAction(UIAlertAction(title: L10n.Alerts.incomingCallButtonIgnore, style: UIAlertActionStyle.default, handler: { (_) in
self.injectionBag.callService.refuse(callId: call.callId)
.subscribe({_ in
print("Call ignored")
}).disposed(by: self.disposeBag)
alert.dismiss(animated: true, completion: nil)
}))
self.present(viewController: alert, withStyle: .present, withAnimation: true)
if UIApplication.shared.applicationState != .active && !call.callId.isEmpty {
var data = [String: String]()
data [NotificationUserInfoKeys.name.rawValue] = call.participantRingId
data [NotificationUserInfoKeys.callID.rawValue] = call.callId
let helper = LocalNotificationsHelper()
helper.presentCallNotification(data: data, callService: self.callService)
} else {
let alertStyle = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad) ? UIAlertControllerStyle.alert : UIAlertControllerStyle.actionSheet
let alert = UIAlertController(title: L10n.Alerts.incomingCallAllertTitle + "\(call.displayName)", message: nil, preferredStyle: alertStyle)
alert.addAction(UIAlertAction(title: L10n.Alerts.incomingCallButtonAccept, style: UIAlertActionStyle.default, handler: { (_) in
self.answerIncomingCall(call: call)
alert.dismiss(animated: true, completion: nil)}))
alert.addAction(UIAlertAction(title: L10n.Alerts.incomingCallButtonIgnore, style: UIAlertActionStyle.default, handler: { (_) in
self.injectionBag.callService.refuse(callId: call.callId)
.subscribe({_ in
print("Call ignored")
}).disposed(by: self.disposeBag)
alert.dismiss(animated: true, completion: nil)
}))
self.present(viewController: alert, withStyle: .present, withAnimation: true)
}
}
}
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
*
* Author: Kateryna Kostiuk <kateryna.kostiuk@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.
*/
import Foundation
import RxSwift
enum NotificationUserInfoKeys: String {
case callID
case name
case messageContent
}
enum NotificationCallTitle: String {
case incomingCall = "Incoming Call"
case missedCall = "Missed Call"
}
enum CallAcition: String {
case accept = "ACCEPT_ACTION"
case refuse = "REFUSE_ACTION"
func title() -> String {
switch self {
case .accept:
return "ACCEPT"
case .refuse:
return "REFUSE"
}
}
}
class LocalNotificationsHelper {
let disposeBag = DisposeBag()
let callCategory = "CALL_CATEGORY"
var timer: Timer?
init() {
self.createCallCategory()
}
func presentMessageNotification(data: [String: String]) {
guard let title = data [NotificationUserInfoKeys.name.rawValue],
let body = data [NotificationUserInfoKeys.messageContent.rawValue] else {
return
}
if #available(iOS 10.0, *) {
let content = UNMutableNotificationContent()
content.title = title
content.body = body
content.badge = UIApplication.shared.applicationIconBadgeNumber + 1 as NSNumber
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.01, repeats: false)
let identifier = Int64(arc4random_uniform(10000000))
let notificationRequest = UNNotificationRequest(identifier: "\(identifier)", content: content, trigger: notificationTrigger)
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
} else {
let notification = UILocalNotification()
notification.alertTitle = title
notification.alertBody = body
notification.applicationIconBadgeNumber = UIApplication.shared.applicationIconBadgeNumber + 1
UIApplication.shared.scheduleLocalNotification(notification)
}
}
func createCallCategory() {
if #available(iOS 10.0, *) {
let acceptAction = UNNotificationAction(identifier: CallAcition.accept.rawValue,
title: CallAcition.accept.title(),
options: [.foreground])
let refuseAction = UNNotificationAction(identifier: CallAcition.refuse.rawValue,
title: CallAcition.refuse.title(),
options: [])
let callCategory = UNNotificationCategory(identifier: self.callCategory,
actions: [acceptAction, refuseAction],
intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([callCategory])
} else {
let notificationTypes: UIUserNotificationType = (UIApplication.shared.currentUserNotificationSettings?.types)!
let acceptAction = UIMutableUserNotificationAction()
acceptAction.identifier = CallAcition.accept.rawValue
acceptAction.title = CallAcition.accept.title()
acceptAction.activationMode = UIUserNotificationActivationMode.foreground
let refuseAction = UIMutableUserNotificationAction()
refuseAction.identifier = CallAcition.refuse.rawValue
refuseAction.title = CallAcition.refuse.title()
refuseAction.activationMode = UIUserNotificationActivationMode.background
let callCategory = UIMutableUserNotificationCategory()
callCategory.identifier = self.callCategory
// A. Set actions for the default context
callCategory.setActions([acceptAction, refuseAction],
for: UIUserNotificationActionContext.default)
// B. Set actions for the minimal context
callCategory.setActions([acceptAction, refuseAction],
for: UIUserNotificationActionContext.minimal)
guard let categoriesForSettings: Set<UIUserNotificationCategory> = NSSet(objects: callCategory) as? Set<UIUserNotificationCategory> else {
return
}
let newNotificationSettings = UIUserNotificationSettings(types: notificationTypes, categories: categoriesForSettings)
UIApplication.shared.registerUserNotificationSettings(newNotificationSettings)
}
}
@objc func cancelCall(timer: Timer!) {
guard let info = timer.userInfo as? [String: String],
let callID = info[NotificationUserInfoKeys.callID.rawValue] else {
self.timer?.invalidate()
self.timer = nil
return
}
var data = [String: String]()
data[NotificationUserInfoKeys.callID.rawValue] = callID
NotificationCenter.default.post(name: NSNotification.Name(NotificationName.refuseCallFromNotifications.rawValue), object: nil, userInfo: data)
self.timer?.invalidate()
self.timer = nil
}
func presentCallNotification(data: [String: String], callService: CallsService) {
let title = NotificationCallTitle.incomingCall.rawValue
guard let name = data [NotificationUserInfoKeys.name.rawValue],
let callID = data [NotificationUserInfoKeys.callID.rawValue] else {
return
}
timer = Timer.scheduledTimer(timeInterval: 10,
target: self,
selector: #selector(cancelCall),
userInfo: [NotificationUserInfoKeys.callID.rawValue: callID],
repeats: false)
if #available(iOS 10.0, *) {
let content = UNMutableNotificationContent()
content.title = title
content.body = name
content.userInfo = data
content.categoryIdentifier = self.callCategory
content.sound = UNNotificationSound(named: "defaul.wav")
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.01, repeats: false)
let notificationRequest = UNNotificationRequest(identifier: callID, content: content, trigger: notificationTrigger)
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
callService.currentCall.filter({ call in
return call.callId == callID && (call.state == .over || call.state == .failure)
}).single()
.subscribe(onNext: { _ in
let content = UNMutableNotificationContent()
content.title = NotificationCallTitle.missedCall.rawValue
content.body = name
content.badge = UIApplication.shared.applicationIconBadgeNumber + 1 as NSNumber
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.01, repeats: false)
let notificationRequest = UNNotificationRequest(identifier: callID, content: content, trigger: notificationTrigger)
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}).disposed(by: self.disposeBag)
} else {
let notification = UILocalNotification()
notification.userInfo = data
notification.alertTitle = title
notification.alertBody = name
notification.category = self.callCategory
notification.applicationIconBadgeNumber = UIApplication.shared.applicationIconBadgeNumber + 1
UIApplication.shared.scheduleLocalNotification(notification)
callService.currentCall.filter({ call in
return call.callId == callID && (call.state == .over || call.state == .failure)
}).single()
.subscribe(onNext: { _ in
let notification = UILocalNotification()
notification.userInfo = data
notification.alertTitle = NotificationCallTitle.missedCall.rawValue
notification.alertBody = name
notification.applicationIconBadgeNumber = UIApplication.shared.applicationIconBadgeNumber + 1
UIApplication.shared.scheduleLocalNotification(notification)
}).disposed(by: self.disposeBag)
}
}
}
......@@ -36,6 +36,8 @@ enum AddAccountError: Error {
enum NotificationName: String {
case enablePushNotifications
case disablePushNotifications
case answerCallFromNotifications
case refuseCallFromNotifications
}
class AccountsService: AccountAdapterDelegate {
......
......@@ -69,6 +69,28 @@ class CallsService: CallsAdapterDelegate {
self.responseStream.disposed(by: disposeBag)
self.sharedResponseStream = responseStream.share()
CallsAdapter.delegate = self
NotificationCenter.default.addObserver(self, selector: #selector(self.refuseUnansweredCall(_:)),
name: NSNotification.Name(rawValue: NotificationName.refuseCallFromNotifications.rawValue),
object: nil)
}
@objc func refuseUnansweredCall(_ notification: NSNotification) {
guard let callid = notification.userInfo?[NotificationUserInfoKeys.callID.rawValue] as? String else {
return
}
guard let call = self.call(callID: callid) else {
return
}
if call.state == .incoming {
self.refuse(callId: callid).subscribe({_ in
print("Call ignored")
}).disposed(by: self.disposeBag)
}
}
func call(callID: String) -> CallModel? {
return self.calls[callID]
}
func accept(call: CallModel?) -> Completable {
......
......@@ -25,12 +25,15 @@ class ConversationsManager: MessagesAdapterDelegate {
let conversationService: ConversationsService
let accountsService: AccountsService
let disposeBag = DisposeBag()
let nameService: NameService
private let disposeBag = DisposeBag()
fileprivate let textPlainMIMEType = "text/plain"
private let notificationHandler = LocalNotificationsHelper()
init(with conversationService: ConversationsService, accountsService: AccountsService) {
init(with conversationService: ConversationsService, accountsService: AccountsService, nameService: NameService) {
self.conversationService = conversationService
self.accountsService = accountsService
self.nameService = nameService
MessagesAdapter.delegate = self
self.accountsService
.sharedResponseStream
......@@ -66,6 +69,27 @@ class ConversationsManager: MessagesAdapterDelegate {
return
}
if UIApplication.shared.applicationState != .active {
var data = [String: String]()
data [NotificationUserInfoKeys.messageContent.rawValue] = content
self.nameService.usernameLookupStatus.single()
.filter({ lookupNameResponse in
return lookupNameResponse.address != nil &&
lookupNameResponse.address == senderAccount
})
.subscribe(onNext: { [weak self] lookupNameResponse in
if let name = lookupNameResponse.name, !name.isEmpty {
data [NotificationUserInfoKeys.name.rawValue] = name
self?.notificationHandler.presentMessageNotification(data: data)
} else if let address = lookupNameResponse.address {
data [NotificationUserInfoKeys.name.rawValue] = address
self?.notificationHandler.presentMessageNotification(data: data)
}
}).disposed(by: self.disposeBag)
self.nameService.lookupAddress(withAccount: "", nameserver: "", address: senderAccount)
}
guard let currentAccount = self.accountsService.currentAccount else {
return
}
......@@ -107,5 +131,4 @@ class ConversationsManager: MessagesAdapterDelegate {
from: accountId,
to: uri)
}
}
......@@ -237,6 +237,10 @@ class ConversationsService {
})
}
func getProfile(uri: String) -> Observable<Profile> {
return self.dbManager.profileObservable(for: uri, createIfNotExists: false)
}
func deleteConversation(conversation: ConversationModel) {
self.dbManager.removeConversationBetween(accountUri: conversation.accountUri, and: conversation.recipientRingId)
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment