mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
806 lines
43 KiB
Swift
806 lines
43 KiB
Swift
import Foundation
|
|
import Postbox
|
|
import TelegramCore
|
|
import SwiftSignalKit
|
|
import UserNotifications
|
|
import TelegramUI
|
|
|
|
private func notificationKey(_ requestId: NotificationManagedNotificationRequestId) -> String {
|
|
switch requestId {
|
|
case let .messageId(id):
|
|
return "m\(id.peerId.toInt64()):\(id.namespace):\(id.id)"
|
|
case let .globallyUniqueId(id, _):
|
|
return "m\(id)"
|
|
}
|
|
}
|
|
|
|
private func processedSoundName(_ name: String) -> String {
|
|
if name.hasSuffix("m4a") {
|
|
return name
|
|
} else {
|
|
return "\(name).m4a"
|
|
}
|
|
}
|
|
|
|
final class NotificationManager {
|
|
private var processedMessages = Set<MessageId>()
|
|
|
|
/*var context: AccountContext? {
|
|
didSet {
|
|
assert(Queue.mainQueue().isCurrent())
|
|
|
|
if let context = self.context {
|
|
self.notificationMessagesDisposable.set((context.account.stateManager.notificationMessages
|
|
|> deliverOn(Queue.mainQueue())).start(next: { [weak self] messages in
|
|
guard let strongSelf = self else {
|
|
return
|
|
}
|
|
var list: [([Message], PeerMessageSound, Bool, Bool)] = []
|
|
for (messageGroup, _, notify) in messages {
|
|
list.append((messageGroup, .default, !strongSelf.isApplicationLocked, false))
|
|
}
|
|
//self?.processNotificationMessages(list, isLocked: strongSelf.isApplicationLocked)
|
|
}))
|
|
} else {
|
|
self.notificationMessagesDisposable.set(nil)
|
|
}
|
|
}
|
|
}*/
|
|
|
|
private let notificationCallStateDisposable = MetaDisposable()
|
|
private(set) var notificationCall: PresentationCall?
|
|
|
|
func setNotificationCall(_ call: PresentationCall?, strings: PresentationStrings) {
|
|
if self.notificationCall?.internalId != call?.internalId {
|
|
self.notificationCall = call
|
|
if let notificationCall = self.notificationCall {
|
|
let peer = notificationCall.peer
|
|
let internalId = notificationCall.internalId
|
|
let isIntegratedWithCallKit = notificationCall.isIntegratedWithCallKit
|
|
self.notificationCallStateDisposable.set((notificationCall.state
|
|
|> map { state -> (Peer?, CallSessionInternalId)? in
|
|
if isIntegratedWithCallKit {
|
|
return nil
|
|
}
|
|
if case .ringing = state {
|
|
return (peer, internalId)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|> distinctUntilChanged(isEqual: { $0?.1 == $1?.1 })).start(next: { [weak self] peerAndInternalId in
|
|
self?.updateNotificationCall(call: peerAndInternalId, strings: strings)
|
|
}))
|
|
} else {
|
|
self.notificationCallStateDisposable.set(nil)
|
|
self.updateNotificationCall(call: nil, strings: strings)
|
|
}
|
|
}
|
|
}
|
|
|
|
private let notificationMessagesDisposable = MetaDisposable()
|
|
|
|
private var notificationRequests: [NotificationManagedNotificationRequestId: Double] = [:]
|
|
private var processedRequestIds = Set<NotificationManagedNotificationRequestId>()
|
|
|
|
var isApplicationInForeground: Bool = false
|
|
var isApplicationLocked: Bool = false
|
|
|
|
deinit {
|
|
self.notificationMessagesDisposable.dispose()
|
|
}
|
|
|
|
func enqueueRemoteNotification(title: String, text: String, apnsSound: String?, requestId: NotificationManagedNotificationRequestId, strings: PresentationStrings, accessChallengeData: PostboxAccessChallengeData) {
|
|
if notificationRequests[requestId] == nil && !processedRequestIds.contains(requestId) {
|
|
var isLocked = false
|
|
if isAccessLocked(data: accessChallengeData, at: Int32(CFAbsoluteTimeGetCurrent())) {
|
|
isLocked = true
|
|
}
|
|
|
|
var userInfo: [AnyHashable: Any]?
|
|
let category: String
|
|
let delay: Bool
|
|
var threadIdentifier: String?
|
|
switch requestId {
|
|
case let .messageId(messageId):
|
|
if messageId.namespace == Namespaces.Message.Local {
|
|
delay = false
|
|
} else {
|
|
delay = true
|
|
}
|
|
userInfo = ["peerId": messageId.peerId.toInt64()]
|
|
threadIdentifier = "peer_\(messageId.peerId.toInt64())"
|
|
if messageId.peerId.namespace == Namespaces.Peer.CloudUser || messageId.peerId.namespace == Namespaces.Peer.CloudGroup {
|
|
category = "withReply"
|
|
} else {
|
|
category = "withMute"
|
|
}
|
|
case let .globallyUniqueId(_, peerId):
|
|
delay = false
|
|
category = "secret"
|
|
if let peerId = peerId {
|
|
userInfo = ["peerId": peerId.toInt64()]
|
|
threadIdentifier = "peer_\(peerId.toInt64())"
|
|
}
|
|
}
|
|
|
|
if #available(iOS 10.0, *) {
|
|
let content = UNMutableNotificationContent()
|
|
if isLocked {
|
|
content.body = strings.PUSH_LOCKED_MESSAGE("").0
|
|
} else {
|
|
if title.isEmpty {
|
|
content.body = text
|
|
} else {
|
|
content.body = "\(title): \(text)"
|
|
}
|
|
}
|
|
if let apnsSound = apnsSound {
|
|
if apnsSound == "0" {
|
|
content.sound = nil
|
|
} else {
|
|
content.sound = UNNotificationSound(named: processedSoundName(apnsSound))
|
|
}
|
|
} else {
|
|
content.sound = UNNotificationSound(named: "0.m4a")
|
|
}
|
|
if let threadIdentifier = threadIdentifier {
|
|
content.threadIdentifier = threadIdentifier
|
|
}
|
|
|
|
content.categoryIdentifier = category
|
|
if let userInfo = userInfo {
|
|
content.userInfo = userInfo
|
|
}
|
|
|
|
let request = UNNotificationRequest(identifier: notificationKey(requestId), content: content, trigger: delay ? UNTimeIntervalNotificationTrigger(timeInterval: 25.0, repeats: false) : nil)
|
|
|
|
let center = UNUserNotificationCenter.current()
|
|
Logger.shared.log("NotificationManager", "adding \(requestId), delay: \(delay)")
|
|
center.add(request, withCompletionHandler: { error in
|
|
if let error = error {
|
|
Logger.shared.log("NotificationManager", "error adding \(requestId), delay: \(delay), error: \(String(describing: error))")
|
|
}
|
|
})
|
|
|
|
if delay {
|
|
notificationRequests[requestId] = CFAbsoluteTimeGetCurrent() + 25.0
|
|
}
|
|
} else {
|
|
let notification = UILocalNotification()
|
|
if isLocked {
|
|
notification.alertBody = strings.PUSH_LOCKED_MESSAGE("").0
|
|
} else {
|
|
if #available(iOS 8.2, *) {
|
|
notification.alertTitle = title
|
|
notification.alertBody = text
|
|
} else {
|
|
if !title.isEmpty {
|
|
notification.alertBody = title + ": " + text
|
|
} else {
|
|
notification.alertBody = text
|
|
}
|
|
}
|
|
}
|
|
notification.category = category
|
|
var updatedUserInfo = userInfo ?? [:]
|
|
updatedUserInfo["id"] = notificationKey(requestId)
|
|
notification.userInfo = updatedUserInfo
|
|
if delay {
|
|
notification.fireDate = Date(timeIntervalSinceNow: 25.0)
|
|
}
|
|
if let apnsSound = apnsSound {
|
|
if apnsSound == "0" {
|
|
notification.soundName = nil
|
|
} else {
|
|
notification.soundName = processedSoundName(apnsSound)
|
|
}
|
|
} else {
|
|
notification.soundName = "0.m4a"
|
|
}
|
|
UIApplication.shared.scheduleLocalNotification(notification)
|
|
|
|
if delay {
|
|
notificationRequests[requestId] = CFAbsoluteTimeGetCurrent() + 25.0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func commitRemoteNotification(context: AccountContext, originalRequestId: NotificationManagedNotificationRequestId?, messageIds: [MessageId]) -> Signal<Void, NoError> {
|
|
return context.account.postbox.transaction { transaction -> ([(MessageId, [Message], Bool, PeerMessageSound, Bool)], Bool) in
|
|
var isLocked = false
|
|
/*if isAccessLocked(data: transaction.getAccessChallengeData(), at: Int32(CFAbsoluteTimeGetCurrent())) {
|
|
isLocked = true
|
|
}*/
|
|
|
|
var results: [(MessageId, [Message], Bool, PeerMessageSound, Bool)] = []
|
|
var updatedMessageIds = messageIds
|
|
if let originalRequestId = originalRequestId {
|
|
switch originalRequestId {
|
|
case let .messageId(id):
|
|
if !updatedMessageIds.contains(id) {
|
|
updatedMessageIds.append(id)
|
|
}
|
|
case .globallyUniqueId:
|
|
break
|
|
}
|
|
}
|
|
for id in updatedMessageIds {
|
|
let (messages, notify, sound, displayContents) = messagesForNotification(transaction: transaction, id: id, alwaysReturnMessage: true)
|
|
|
|
if results.contains(where: { result in
|
|
return result.1.contains(where: { message in
|
|
return messages.contains(where: {
|
|
message.id == $0.id
|
|
})
|
|
})
|
|
}) {
|
|
continue
|
|
}
|
|
results.append((id, messages, notify, sound, displayContents))
|
|
}
|
|
return (results, isLocked)
|
|
}
|
|
|> deliverOnMainQueue
|
|
|> beforeNext {
|
|
[weak self] results, isLocked in
|
|
if let strongSelf = self {
|
|
let delayUntilTimestamp: Int32 = context.account.stateManager.getDelayNotificatonsUntil() ?? 0
|
|
|
|
for (id, messages, notify, sound, displayContents) in results {
|
|
let requestId: NotificationManagedNotificationRequestId = .messageId(id)
|
|
if let message = messages.first, message.id.peerId.namespace != Namespaces.Peer.SecretChat, !strongSelf.processedRequestIds.contains(requestId) {
|
|
let notificationRequestTimeout = strongSelf.notificationRequests[requestId]
|
|
if notificationRequestTimeout == nil || CFAbsoluteTimeGetCurrent() < notificationRequestTimeout! {
|
|
if #available(iOS 10.0, *) {
|
|
let center = UNUserNotificationCenter.current()
|
|
center.removePendingNotificationRequests(withIdentifiers: [notificationKey(requestId)])
|
|
} else {
|
|
let key = notificationKey(requestId)
|
|
if let notifications = UIApplication.shared.scheduledLocalNotifications {
|
|
for notification in notifications {
|
|
if let userInfo = notification.userInfo, let id = userInfo["id"] as? String {
|
|
if id == key {
|
|
UIApplication.shared.cancelLocalNotification(notification)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if !strongSelf.processedRequestIds.contains(requestId) {
|
|
strongSelf.processedRequestIds.insert(requestId)
|
|
|
|
if notify {
|
|
var delayMessage = false
|
|
if message.timestamp <= delayUntilTimestamp && message.id.peerId.namespace != Namespaces.Peer.SecretChat {
|
|
delayMessage = true
|
|
}
|
|
strongSelf.processNotificationMessages(context: context, messageList: [(messages, sound, displayContents, delayMessage)], isLocked: isLocked)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |> map { _ in
|
|
return Void()
|
|
}
|
|
}
|
|
|
|
private func processNotificationMessages(context: AccountContext, messageList: [([Message], PeerMessageSound, Bool, Bool)], isLocked: Bool) {
|
|
let presentationData = (context.sharedContext.currentPresentationData.with { $0 })
|
|
let strings = presentationData.strings
|
|
let nameDisplayOrder = presentationData.nameDisplayOrder
|
|
|
|
for (messages, sound, initialDisplayContents, delayMessage) in messageList {
|
|
for message in messages {
|
|
self.processedMessages.insert(message.id)
|
|
}
|
|
guard let firstMessage = messages.first else {
|
|
continue
|
|
}
|
|
let displayContents = initialDisplayContents && !isLocked
|
|
|
|
let requestId: NotificationManagedNotificationRequestId
|
|
if let globallyUniqueId = firstMessage.globallyUniqueId, firstMessage.id.peerId.namespace == Namespaces.Peer.SecretChat {
|
|
requestId = .globallyUniqueId(globallyUniqueId, firstMessage.id.peerId)
|
|
} else {
|
|
requestId = .messageId(firstMessage.id)
|
|
}
|
|
|
|
let notificationRequestTimeout = notificationRequests[requestId]
|
|
|
|
if notificationRequestTimeout == nil || CFAbsoluteTimeGetCurrent() < notificationRequestTimeout! {
|
|
if self.isApplicationInForeground {
|
|
processedRequestIds.insert(requestId)
|
|
if notificationRequestTimeout != nil {
|
|
if #available(iOS 10.0, *) {
|
|
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notificationKey(requestId)])
|
|
} else {
|
|
let key = notificationKey(requestId)
|
|
if let notifications = UIApplication.shared.scheduledLocalNotifications {
|
|
for notification in notifications {
|
|
if let userInfo = notification.userInfo, let id = userInfo["id"] as? String {
|
|
if id == key {
|
|
UIApplication.shared.cancelLocalNotification(notification)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
var title: String?
|
|
var body: String
|
|
var mediaRepresentations: [TelegramMediaImageRepresentation]?
|
|
var mediaInfo: [String: Any]? = nil
|
|
|
|
body = firstMessage.text
|
|
if let peer = messageMainPeer(firstMessage) {
|
|
var displayAuthor = true
|
|
if let channel = peer as? TelegramChannel {
|
|
switch channel.info {
|
|
case .group:
|
|
displayAuthor = true
|
|
case .broadcast:
|
|
displayAuthor = false
|
|
}
|
|
} else if let _ = peer as? TelegramUser {
|
|
displayAuthor = false
|
|
}
|
|
|
|
if let author = firstMessage.author, displayAuthor {
|
|
title = author.compactDisplayTitle + "@" + peer.displayTitle
|
|
} else {
|
|
title = peer.displayTitle
|
|
}
|
|
|
|
if messages.count > 1 {
|
|
if messages[0].forwardInfo != nil {
|
|
if let author = firstMessage.author, displayAuthor {
|
|
let rawText = presentationData.strings.PUSH_CHAT_MESSAGE_FWDS(Int32(messages.count), peer.displayTitle, author.compactDisplayTitle, Int32(messages.count))
|
|
if let index = rawText.firstIndex(of: "|") {
|
|
title = String(rawText[rawText.startIndex ..< index])
|
|
body = String(rawText[rawText.index(after: index)...])
|
|
} else {
|
|
title = nil
|
|
body = rawText
|
|
}
|
|
} else {
|
|
let rawText = presentationData.strings.PUSH_MESSAGE_FWDS(Int32(messages.count), peer.displayTitle, Int32(messages.count))
|
|
if let index = rawText.firstIndex(of: "|") {
|
|
title = String(rawText[rawText.startIndex ..< index])
|
|
body = String(rawText[rawText.index(after: index)...])
|
|
} else {
|
|
title = nil
|
|
body = rawText
|
|
}
|
|
}
|
|
} else if messages[0].groupingKey != nil {
|
|
var kind = messageContentKind(messages[0], strings: strings, nameDisplayOrder: nameDisplayOrder, accountPeerId: context.account.peerId).key
|
|
for i in 1 ..< messages.count {
|
|
let nextKind = messageContentKind(messages[i], strings: strings, nameDisplayOrder: nameDisplayOrder, accountPeerId: context.account.peerId)
|
|
if kind != nextKind.key {
|
|
kind = .text
|
|
break
|
|
}
|
|
}
|
|
var isChannel = false
|
|
var isGroup = false
|
|
if let peer = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel {
|
|
if case .broadcast = peer.info {
|
|
isChannel = true
|
|
} else {
|
|
isGroup = true
|
|
}
|
|
} else if firstMessage.id.peerId.namespace == Namespaces.Peer.CloudGroup {
|
|
isGroup = true
|
|
}
|
|
title = nil
|
|
if isChannel {
|
|
switch kind {
|
|
case .image:
|
|
let rawText = presentationData.strings.PUSH_CHANNEL_MESSAGE_PHOTOS(Int32(messages.count), peer.displayTitle, Int32(messages.count))
|
|
if let index = rawText.firstIndex(of: "|") {
|
|
title = String(rawText[rawText.startIndex ..< index])
|
|
body = String(rawText[rawText.index(after: index)...])
|
|
} else {
|
|
title = nil
|
|
body = rawText
|
|
}
|
|
default:
|
|
let rawText = presentationData.strings.PUSH_CHANNEL_MESSAGES(Int32(messages.count), peer.displayTitle, Int32(messages.count))
|
|
if let index = rawText.firstIndex(of: "|") {
|
|
title = String(rawText[rawText.startIndex ..< index])
|
|
body = String(rawText[rawText.index(after: index)...])
|
|
} else {
|
|
title = nil
|
|
body = rawText
|
|
}
|
|
}
|
|
} else if isGroup, let author = firstMessage.author {
|
|
switch kind {
|
|
case .image:
|
|
let rawText = presentationData.strings.PUSH_CHAT_MESSAGE_PHOTOS(Int32(messages.count), peer.displayTitle, author.compactDisplayTitle, Int32(messages.count))
|
|
if let index = rawText.firstIndex(of: "|") {
|
|
title = String(rawText[rawText.startIndex ..< index])
|
|
body = String(rawText[rawText.index(after: index)...])
|
|
} else {
|
|
title = nil
|
|
body = rawText
|
|
}
|
|
default:
|
|
let rawText = presentationData.strings.PUSH_CHAT_MESSAGES(Int32(messages.count), peer.displayTitle, author.compactDisplayTitle, Int32(messages.count))
|
|
if let index = rawText.firstIndex(of: "|") {
|
|
title = String(rawText[rawText.startIndex ..< index])
|
|
body = String(rawText[rawText.index(after: index)...])
|
|
} else {
|
|
title = nil
|
|
body = rawText
|
|
}
|
|
}
|
|
} else {
|
|
switch kind {
|
|
case .image:
|
|
let rawText = presentationData.strings.PUSH_MESSAGE_PHOTOS(Int32(messages.count), peer.displayTitle, Int32(messages.count))
|
|
if let index = rawText.firstIndex(of: "|") {
|
|
title = String(rawText[rawText.startIndex ..< index])
|
|
body = String(rawText[rawText.index(after: index)...])
|
|
} else {
|
|
title = nil
|
|
body = rawText
|
|
}
|
|
default:
|
|
let rawText = presentationData.strings.PUSH_MESSAGES(Int32(messages.count), peer.displayTitle, Int32(messages.count))
|
|
if let index = rawText.firstIndex(of: "|") {
|
|
title = String(rawText[rawText.startIndex ..< index])
|
|
body = String(rawText[rawText.index(after: index)...])
|
|
} else {
|
|
title = nil
|
|
body = rawText
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if messages.count == 1 {
|
|
let additionalPeers = firstMessage.peers
|
|
var isPin = false
|
|
for media in messages[0].media {
|
|
if let action = media as? TelegramMediaAction {
|
|
if case .pinnedMessageUpdated = action.action {
|
|
isPin = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if let channel = peer as? TelegramChannel, case .broadcast = channel.info, isPin {
|
|
title = nil
|
|
}
|
|
let chatPeer = RenderedPeer(peerId: firstMessage.id.peerId, peers: additionalPeers)
|
|
let (_, _, messageText) = chatListItemStrings(strings: strings, nameDisplayOrder: nameDisplayOrder, message: firstMessage, chatPeer: chatPeer, accountPeerId: context.account.peerId)
|
|
body = messageText
|
|
|
|
loop: for media in firstMessage.media {
|
|
if let image = media as? TelegramMediaImage {
|
|
mediaRepresentations = image.representations
|
|
if !firstMessage.containsSecretMedia, let smallest = smallestImageRepresentation(image.representations), let largest = largestImageRepresentation(image.representations) {
|
|
var imageInfo: [String: Any] = [:]
|
|
|
|
var thumbnailInfo: [String: Any] = [:]
|
|
thumbnailInfo["path"] = context.account.postbox.mediaBox.resourcePath(smallest.resource)
|
|
imageInfo["thumbnail"] = thumbnailInfo
|
|
|
|
var fullSizeInfo: [String: Any] = [:]
|
|
fullSizeInfo["path"] = context.account.postbox.mediaBox.resourcePath(largest.resource)
|
|
imageInfo["fullSize"] = fullSizeInfo
|
|
|
|
imageInfo["width"] = Int(largest.dimensions.width)
|
|
imageInfo["height"] = Int(largest.dimensions.height)
|
|
|
|
mediaInfo = ["image": imageInfo]
|
|
}
|
|
break loop
|
|
} else if let file = media as? TelegramMediaFile {
|
|
if !firstMessage.containsSecretMedia {
|
|
//mediaRepresentations = file.previewRepresentations
|
|
}
|
|
break loop
|
|
} else if let location = media as? TelegramMediaMap {
|
|
if location.liveBroadcastingTimeout != nil {
|
|
if let chatMainPeer = chatPeer.chatMainPeer {
|
|
if let user = chatMainPeer as? TelegramUser {
|
|
body = strings.PUSH_MESSAGE_GEOLIVE(user.displayTitle).0
|
|
} else if let _ = chatMainPeer as? TelegramGroup, let author = firstMessage.author {
|
|
body = strings.PUSH_MESSAGE_GEOLIVE(author.displayTitle).0
|
|
} else if let channel = chatMainPeer as? TelegramChannel {
|
|
switch channel.info {
|
|
case .group:
|
|
if let author = firstMessage.author {
|
|
body = strings.PUSH_MESSAGE_GEOLIVE(author.displayTitle).0
|
|
}
|
|
case .broadcast:
|
|
body = strings.PUSH_CHANNEL_MESSAGE_GEOLIVE(chatMainPeer.displayTitle).0
|
|
}
|
|
}
|
|
}
|
|
break loop
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
body = strings.PUSH_ENCRYPTED_MESSAGE("").0
|
|
}
|
|
|
|
if isLocked {
|
|
title = nil
|
|
}
|
|
if !displayContents {
|
|
body = strings.PUSH_ENCRYPTED_MESSAGE("").0
|
|
}
|
|
|
|
var userInfo: [AnyHashable: Any] = ["peerId": firstMessage.id.peerId.toInt64()]
|
|
userInfo["messageId.namespace"] = firstMessage.id.namespace
|
|
userInfo["messageId.id"] = firstMessage.id.id
|
|
let category: String
|
|
if displayContents, let peer = firstMessage.peers[firstMessage.id.peerId] {
|
|
switch peer {
|
|
case _ as TelegramUser:
|
|
if let mediaInfo = mediaInfo {
|
|
category = "withReplyMedia"
|
|
userInfo["mediaInfo"] = mediaInfo
|
|
} else {
|
|
category = "withReply"
|
|
}
|
|
case _ as TelegramGroup:
|
|
if let mediaInfo = mediaInfo {
|
|
category = "withReplyMedia"
|
|
userInfo["mediaInfo"] = mediaInfo
|
|
} else {
|
|
category = "withReply"
|
|
}
|
|
case let channel as TelegramChannel:
|
|
if case .group = channel.info {
|
|
if let mediaInfo = mediaInfo {
|
|
category = "withReplyMedia"
|
|
userInfo["mediaInfo"] = mediaInfo
|
|
} else {
|
|
category = "withReply"
|
|
}
|
|
} else {
|
|
if let mediaInfo = mediaInfo {
|
|
category = "withMuteMedia"
|
|
userInfo["mediaInfo"] = mediaInfo
|
|
} else {
|
|
category = "withMute"
|
|
}
|
|
}
|
|
default:
|
|
category = "withMute"
|
|
}
|
|
} else {
|
|
category = "withMute"
|
|
}
|
|
|
|
if #available(iOS 10.0, *) {
|
|
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notificationKey(requestId)])
|
|
|
|
let content = UNMutableNotificationContent()
|
|
if let title = title {
|
|
content.title = title
|
|
}
|
|
content.body = body
|
|
switch sound {
|
|
case .none:
|
|
content.sound = nil
|
|
case .default:
|
|
content.sound = UNNotificationSound(named: "0.m4a")
|
|
default:
|
|
content.sound = UNNotificationSound(named: fileNameForNotificationSound(sound, defaultSound: nil) + ".m4a")
|
|
}
|
|
content.categoryIdentifier = category
|
|
content.userInfo = userInfo
|
|
|
|
content.threadIdentifier = "peer_\(firstMessage.id.peerId.toInt64())"
|
|
|
|
if mediaInfo != nil, let mediaRepresentations = mediaRepresentations {
|
|
if let smallest = smallestImageRepresentation(mediaRepresentations) {
|
|
/*if let path = account.postbox.mediaBox.completedResourcePath(smallest.resource) {
|
|
var randomId: Int64 = 0
|
|
arc4random_buf(&randomId, 8)
|
|
let tempPath = NSTemporaryDirectory() + "/\(randomId).jpg"
|
|
if let _ = try? FileManager.default.copyItem(atPath: path, toPath: tempPath) {
|
|
if let attachment = try? UNNotificationAttachment(identifier: "image", url: URL(fileURLWithPath: tempPath)) {
|
|
content.attachments = [attachment]
|
|
}
|
|
}
|
|
}*/
|
|
}
|
|
}
|
|
|
|
var trigger: UNTimeIntervalNotificationTrigger?
|
|
if delayMessage {
|
|
trigger = UNTimeIntervalNotificationTrigger(timeInterval: 25.0, repeats: false)
|
|
}
|
|
let request = UNNotificationRequest(identifier: notificationKey(requestId) + "_", content: content, trigger: trigger)
|
|
|
|
let center = UNUserNotificationCenter.current()
|
|
Logger.shared.log("NotificationManager", "adding \(requestId), delay: \(delayMessage)")
|
|
center.add(request, withCompletionHandler: { error in
|
|
if let error = error {
|
|
Logger.shared.log("NotificationManager", "error adding \(requestId), delay: \(delayMessage), error: \(String(describing: error))")
|
|
}
|
|
})
|
|
processedRequestIds.insert(requestId)
|
|
} else {
|
|
let key = notificationKey(requestId)
|
|
if let notifications = UIApplication.shared.scheduledLocalNotifications {
|
|
for notification in notifications {
|
|
if let userInfo = notification.userInfo, let id = userInfo["id"] as? String {
|
|
if id == key {
|
|
UIApplication.shared.cancelLocalNotification(notification)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
let notification = UILocalNotification()
|
|
if #available(iOS 10.0, *) {
|
|
notification.alertTitle = title
|
|
notification.alertBody = body
|
|
} else {
|
|
if let title = title {
|
|
notification.alertBody = title + ": " + body
|
|
} else {
|
|
notification.alertBody = body
|
|
}
|
|
}
|
|
notification.category = category
|
|
var updatedUserInfo = userInfo
|
|
updatedUserInfo["id"] = notificationKey(requestId) + "_"
|
|
notification.userInfo = userInfo
|
|
switch sound {
|
|
case .none:
|
|
notification.soundName = nil
|
|
case .default:
|
|
notification.soundName = "0.m4a"
|
|
default:
|
|
notification.soundName = fileNameForNotificationSound(sound, defaultSound: nil) + ".m4a"
|
|
}
|
|
|
|
UIApplication.shared.presentLocalNotificationNow(notification)
|
|
}
|
|
}
|
|
} else {
|
|
Logger.shared.log("NotificationManager", "not showing message because of timeout")
|
|
}
|
|
self.notificationRequests.removeValue(forKey: requestId)
|
|
}
|
|
}
|
|
|
|
private var currentNotificationCall: (peer: Peer?, internalId: CallSessionInternalId)?
|
|
|
|
private func updateNotificationCall(call: (peer: Peer?, internalId: CallSessionInternalId)?, strings: PresentationStrings) {
|
|
if let previousCall = currentNotificationCall {
|
|
if #available(iOS 10.0, *) {
|
|
let center = UNUserNotificationCenter.current()
|
|
center.removeDeliveredNotifications(withIdentifiers: ["call_\(previousCall.internalId)"])
|
|
} else {
|
|
if let notifications = UIApplication.shared.scheduledLocalNotifications {
|
|
for notification in notifications {
|
|
if let userInfo = notification.userInfo, let callId = userInfo["callId"] as? String, callId == String(describing: previousCall.internalId) {
|
|
UIApplication.shared.cancelLocalNotification(notification)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
self.currentNotificationCall = call
|
|
|
|
if let notificationCall = call {
|
|
let rawText = strings.PUSH_PHONE_CALL_REQUEST(notificationCall.peer?.displayTitle ?? "").0
|
|
let title: String?
|
|
let body: String
|
|
if let index = rawText.firstIndex(of: "|") {
|
|
title = String(rawText[rawText.startIndex ..< index])
|
|
body = String(rawText[rawText.index(after: index)...])
|
|
} else {
|
|
title = nil
|
|
body = rawText
|
|
}
|
|
|
|
if #available(iOS 10.0, *) {
|
|
let content = UNMutableNotificationContent()
|
|
if let title = title {
|
|
content.title = title
|
|
}
|
|
content.body = body
|
|
content.sound = UNNotificationSound(named: "0.m4a")
|
|
content.categoryIdentifier = "incomingCall"
|
|
content.userInfo = [:]
|
|
|
|
let request = UNNotificationRequest(identifier: "call_\(notificationCall.internalId)", content: content, trigger: nil)
|
|
|
|
let center = UNUserNotificationCenter.current()
|
|
Logger.shared.log("NotificationManager", "adding call \(notificationCall.internalId)")
|
|
center.add(request, withCompletionHandler: { error in
|
|
if let error = error {
|
|
Logger.shared.log("NotificationManager", "error adding call \(notificationCall.internalId), error: \(String(describing: error))")
|
|
}
|
|
})
|
|
|
|
} else {
|
|
let notification = UILocalNotification()
|
|
if #available(iOS 8.2, *) {
|
|
notification.alertTitle = title
|
|
notification.alertBody = body
|
|
} else {
|
|
if let title = title {
|
|
notification.alertBody = "\(title): \(body)"
|
|
} else {
|
|
notification.alertBody = body
|
|
}
|
|
}
|
|
notification.category = "incomingCall"
|
|
notification.userInfo = ["callId": String(describing: notificationCall.internalId)]
|
|
notification.soundName = "0.m4a"
|
|
UIApplication.shared.presentLocalNotificationNow(notification)
|
|
}
|
|
}
|
|
}
|
|
|
|
func presentWatchContinuityNotification(context: AccountContext, messageId: MessageId) {
|
|
if #available(iOS 10.0, *) {
|
|
let center = UNUserNotificationCenter.current()
|
|
center.removeDeliveredNotifications(withIdentifiers: ["watch"])
|
|
} else {
|
|
if let notifications = UIApplication.shared.scheduledLocalNotifications {
|
|
for notification in notifications {
|
|
if let category = notification.category, category == "watch" {
|
|
UIApplication.shared.cancelLocalNotification(notification)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
|
|
var userInfo: [AnyHashable : Any] = [:]
|
|
userInfo["peerId"] = messageId.peerId.toInt64()
|
|
userInfo["messageId.namespace"] = messageId.namespace
|
|
userInfo["messageId.id"] = messageId.id
|
|
|
|
if #available(iOS 10.0, *) {
|
|
let content = UNMutableNotificationContent()
|
|
content.body = presentationData.strings.WatchRemote_NotificationText
|
|
content.sound = UNNotificationSound(named: "0.m4a")
|
|
content.categoryIdentifier = "watch"
|
|
content.userInfo = userInfo
|
|
|
|
let request = UNNotificationRequest(identifier: "watch", content: content, trigger: nil)
|
|
|
|
let center = UNUserNotificationCenter.current()
|
|
Logger.shared.log("NotificationManager", "adding watch continuity")
|
|
center.add(request, withCompletionHandler: { error in
|
|
if let error = error {
|
|
Logger.shared.log("NotificationManager", "error adding watch continuity, error: \(String(describing: error))")
|
|
}
|
|
})
|
|
|
|
} else {
|
|
let notification = UILocalNotification()
|
|
notification.alertBody = presentationData.strings.WatchRemote_NotificationText
|
|
notification.category = "watch"
|
|
notification.userInfo = userInfo
|
|
notification.soundName = "0.m4a"
|
|
UIApplication.shared.presentLocalNotificationNow(notification)
|
|
}
|
|
}
|
|
}
|