204 lines
8.4 KiB
Swift
204 lines
8.4 KiB
Swift
//
|
||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||
//
|
||
|
||
import Foundation
|
||
import SessionServiceKit
|
||
import SignalMessaging
|
||
import PromiseKit
|
||
|
||
class DebugUINotifications: DebugUIPage {
|
||
|
||
// MARK: Dependencies
|
||
|
||
var notificationPresenter: NotificationPresenter {
|
||
return AppEnvironment.shared.notificationPresenter
|
||
}
|
||
var messageSender: MessageSender {
|
||
return SSKEnvironment.shared.messageSender
|
||
}
|
||
var contactsManager: OWSContactsManager {
|
||
return Environment.shared.contactsManager
|
||
}
|
||
|
||
// MARK: Overrides
|
||
|
||
override func name() -> String {
|
||
return "Notifications"
|
||
}
|
||
|
||
override func section(thread: TSThread?) -> OWSTableSection? {
|
||
guard let thread = thread else {
|
||
owsFailDebug("Notifications must specify thread.")
|
||
return nil
|
||
}
|
||
|
||
var sectionItems: [OWSTableItem] = []
|
||
|
||
if let contactThread = thread as? TSContactThread {
|
||
sectionItems += [
|
||
OWSTableItem(title: "All Notifications in Sequence") { [weak self] in
|
||
self?.notifyForEverythingInSequence(contactThread: contactThread).retainUntilComplete()
|
||
},
|
||
// OWSTableItem(title: "Incoming Call") { [weak self] in
|
||
// self?.notifyForIncomingCall(thread: contactThread).retainUntilComplete()
|
||
// },
|
||
// OWSTableItem(title: "Call Missed") { [weak self] in
|
||
// self?.notifyForMissedCall(thread: contactThread).retainUntilComplete()
|
||
// },
|
||
// OWSTableItem(title: "Call Rejected: New Safety Number") { [weak self] in
|
||
// self?.notifyForMissedCallBecauseOfNewIdentity(thread: contactThread).retainUntilComplete()
|
||
// },
|
||
// OWSTableItem(title: "Call Rejected: No Longer Verified") { [weak self] in
|
||
// self?.notifyForMissedCallBecauseOfNoLongerVerifiedIdentity(thread: contactThread).retainUntilComplete()
|
||
// }
|
||
]
|
||
}
|
||
|
||
sectionItems += [
|
||
OWSTableItem(title: "Last Incoming Message") { [weak self] in
|
||
self?.notifyForIncomingMessage(thread: thread).retainUntilComplete()
|
||
},
|
||
|
||
OWSTableItem(title: "Notify For Error Message") { [weak self] in
|
||
self?.notifyForErrorMessage(thread: thread).retainUntilComplete()
|
||
},
|
||
|
||
OWSTableItem(title: "Notify For Threadless Error Message") { [weak self] in
|
||
self?.notifyUserForThreadlessErrorMessage().retainUntilComplete()
|
||
}
|
||
]
|
||
|
||
return OWSTableSection(title: "Notifications have delay: \(kNotificationDelay)s", items: sectionItems)
|
||
}
|
||
|
||
// MARK: Helpers
|
||
|
||
func readWrite(_ block: @escaping (YapDatabaseReadWriteTransaction) -> Void) {
|
||
OWSPrimaryStorage.shared().dbReadWriteConnection.readWrite(block)
|
||
}
|
||
|
||
// After enqueing the notification you may want to background the app or lock the screen before it triggers, so
|
||
// we give a little delay.
|
||
let kNotificationDelay: TimeInterval = 5
|
||
|
||
func delayedNotificationDispatch(block: @escaping () -> Void) -> Guarantee<Void> {
|
||
Logger.info("delaying for \(kNotificationDelay) seconds")
|
||
|
||
// Notifications won't sound if the app is suspended.
|
||
let taskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
|
||
|
||
return after(seconds: kNotificationDelay).done {
|
||
block()
|
||
}.then {
|
||
after(seconds: 2.0)
|
||
}.done {
|
||
// We don't want to endBackgroundTask until *after* the notifications manager is done,
|
||
// but it dispatches async without a completion handler, so we just wait a while extra.
|
||
// This is fragile, but it's only for debug UI.
|
||
UIApplication.shared.endBackgroundTask(taskIdentifier)
|
||
}
|
||
}
|
||
|
||
// func delayedNotificationDispatchWithFakeCall(thread: TSContactThread, callBlock: @escaping (SignalCall) -> Void) -> Guarantee<Void> {
|
||
// let call = SignalCall.incomingCall(localId: UUID(), remotePhoneNumber: thread.contactIdentifier(), signalingId: 0)
|
||
//
|
||
// return delayedNotificationDispatch {
|
||
// callBlock(call)
|
||
// }
|
||
// }
|
||
|
||
// MARK: Notification Methods
|
||
|
||
func notifyForEverythingInSequence(contactThread: TSContactThread) -> Guarantee<Void> {
|
||
let taskIdentifier = UIApplication.shared.beginBackgroundTask(expirationHandler: nil)
|
||
|
||
// return firstly {
|
||
// self.notifyForIncomingCall(thread: contactThread)
|
||
// }.then {
|
||
// self.notifyForMissedCall(thread: contactThread)
|
||
// }.then {
|
||
// self.notifyForMissedCallBecauseOfNewIdentity(thread: contactThread)
|
||
// }.then {
|
||
// self.notifyForMissedCallBecauseOfNoLongerVerifiedIdentity(thread: contactThread)
|
||
// }.then
|
||
return firstly {
|
||
self.notifyForIncomingMessage(thread: contactThread)
|
||
}.then {
|
||
self.notifyForErrorMessage(thread: contactThread)
|
||
}.then {
|
||
self.notifyUserForThreadlessErrorMessage()
|
||
}.done {
|
||
UIApplication.shared.endBackgroundTask(taskIdentifier)
|
||
}
|
||
}
|
||
|
||
// func notifyForIncomingCall(thread: TSContactThread) -> Guarantee<Void> {
|
||
// Logger.info("⚠️ will present notification after delay")
|
||
// return delayedNotificationDispatchWithFakeCall(thread: thread) { call in
|
||
// self.notificationPresenter.presentIncomingCall(call, callerName: thread.name())
|
||
// }
|
||
// }
|
||
//
|
||
// func notifyForMissedCall(thread: TSContactThread) -> Guarantee<Void> {
|
||
// Logger.info("⚠️ will present notification after delay")
|
||
// return delayedNotificationDispatchWithFakeCall(thread: thread) { call in
|
||
// self.notificationPresenter.presentMissedCall(call, callerName: thread.name())
|
||
// }
|
||
// }
|
||
//
|
||
// func notifyForMissedCallBecauseOfNewIdentity(thread: TSContactThread) -> Guarantee<Void> {
|
||
// Logger.info("⚠️ will present notification after delay")
|
||
// return delayedNotificationDispatchWithFakeCall(thread: thread) { call in
|
||
// self.notificationPresenter.presentMissedCallBecauseOfNewIdentity(call: call, callerName: thread.name())
|
||
// }
|
||
// }
|
||
//
|
||
// func notifyForMissedCallBecauseOfNoLongerVerifiedIdentity(thread: TSContactThread) -> Guarantee<Void> {
|
||
// Logger.info("⚠️ will present notification after delay")
|
||
// return delayedNotificationDispatchWithFakeCall(thread: thread) { call in
|
||
// self.notificationPresenter.presentMissedCallBecauseOfNoLongerVerifiedIdentity(call: call, callerName: thread.name())
|
||
// }
|
||
// }
|
||
|
||
func notifyForIncomingMessage(thread: TSThread) -> Guarantee<Void> {
|
||
Logger.info("⚠️ will present notification after delay")
|
||
return delayedNotificationDispatch {
|
||
self.readWrite { transaction in
|
||
let factory = IncomingMessageFactory()
|
||
factory.threadCreator = { _ in return thread }
|
||
let incomingMessage = factory.create(transaction: transaction)
|
||
|
||
self.notificationPresenter.notifyUser(for: incomingMessage,
|
||
in: thread,
|
||
transaction: transaction)
|
||
}
|
||
}
|
||
}
|
||
|
||
func notifyForErrorMessage(thread: TSThread) -> Guarantee<Void> {
|
||
Logger.info("⚠️ will present notification after delay")
|
||
return delayedNotificationDispatch {
|
||
let errorMessage = TSErrorMessage(timestamp: NSDate.ows_millisecondTimeStamp(),
|
||
in: thread,
|
||
failedMessageType: TSErrorMessageType.invalidMessage)
|
||
|
||
self.readWrite { transaction in
|
||
self.notificationPresenter.notifyUser(for: errorMessage, thread: thread, transaction: transaction)
|
||
}
|
||
}
|
||
}
|
||
|
||
func notifyUserForThreadlessErrorMessage() -> Guarantee<Void> {
|
||
Logger.info("⚠️ will present notification after delay")
|
||
return delayedNotificationDispatch {
|
||
self.readWrite { transaction in
|
||
let errorMessage = TSErrorMessage.corruptedMessageInUnknownThread()
|
||
|
||
self.notificationPresenter.notifyUser(forThreadlessErrorMessage: errorMessage,
|
||
transaction: transaction)
|
||
}
|
||
}
|
||
}
|
||
}
|