mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
248 lines
10 KiB
Swift
248 lines
10 KiB
Swift
import Foundation
|
|
import SwiftSignalKit
|
|
import Postbox
|
|
import TelegramCore
|
|
import SyncCore
|
|
import Contacts
|
|
import Intents
|
|
|
|
extension MessageId {
|
|
init?(string: String) {
|
|
let components = string.components(separatedBy: "_")
|
|
if components.count == 3, let peerIdValue = Int64(components[0]), let namespaceValue = Int32(components[1]), let idValue = Int32(components[2]) {
|
|
self.init(peerId: PeerId(peerIdValue), namespace: namespaceValue, id: idValue)
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
|
|
func getMessages(account: Account, ids: [MessageId]) -> Signal<[INMessage], NoError> {
|
|
return account.postbox.transaction { transaction -> [INMessage] in
|
|
var messages: [INMessage] = []
|
|
for id in ids {
|
|
if let message = transaction.getMessage(id).flatMap(messageWithTelegramMessage) {
|
|
messages.append(message)
|
|
}
|
|
}
|
|
return messages.sorted { $0.dateSent!.compare($1.dateSent!) == .orderedDescending }
|
|
}
|
|
}
|
|
|
|
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
|
|
func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
|
|
return account.postbox.tailChatListView(groupId: .root, count: 20, summaryComponents: ChatListEntrySummaryComponents())
|
|
|> take(1)
|
|
|> mapToSignal { view -> Signal<[INMessage], NoError> in
|
|
var signals: [Signal<[INMessage], NoError>] = []
|
|
for entry in view.0.entries {
|
|
if case let .MessageEntry(index, _, readState, notificationSettings, _, _, _, _, _, _) = entry {
|
|
if index.messageIndex.id.peerId.namespace != Namespaces.Peer.CloudUser {
|
|
continue
|
|
}
|
|
|
|
var hasUnread = false
|
|
var fixedCombinedReadStates: MessageHistoryViewReadState?
|
|
if let readState = readState {
|
|
hasUnread = readState.count != 0
|
|
fixedCombinedReadStates = .peer([index.messageIndex.id.peerId: readState])
|
|
}
|
|
var isMuted = false
|
|
if let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings {
|
|
if case let .muted(until) = notificationSettings.muteState, until >= Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) {
|
|
isMuted = true
|
|
}
|
|
}
|
|
|
|
if !isMuted && hasUnread {
|
|
signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(index.messageIndex.id.peerId), anchor: .upperBound, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: .combinedLocation)
|
|
|> take(1)
|
|
|> map { view -> [INMessage] in
|
|
var messages: [INMessage] = []
|
|
for entry in view.0.entries {
|
|
var isRead = true
|
|
if let readState = readState {
|
|
isRead = readState.isIncomingMessageIndexRead(entry.message.index)
|
|
}
|
|
|
|
if !isRead {
|
|
if let message = messageWithTelegramMessage(entry.message) {
|
|
messages.append(message)
|
|
}
|
|
}
|
|
}
|
|
return messages
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
if signals.isEmpty {
|
|
return .single([])
|
|
} else {
|
|
return combineLatest(signals)
|
|
|> map { results -> [INMessage] in
|
|
return results.flatMap { $0 }.sorted { $0.dateSent!.compare($1.dateSent!) == .orderedDescending }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
|
|
struct CallRecord {
|
|
let identifier: String
|
|
let date: Date
|
|
let caller: INPerson
|
|
let duration: Int32?
|
|
let unseen: Bool
|
|
|
|
@available(iOSApplicationExtension 11.0, iOS 11.0, *)
|
|
var intentCall: INCallRecord {
|
|
return INCallRecord(identifier: self.identifier, dateCreated: self.date, caller: self.caller, callRecordType: .missed, callCapability: .audioCall, callDuration: self.duration.flatMap(Double.init), unseen: self.unseen)
|
|
}
|
|
}
|
|
|
|
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
|
|
func missedCalls(account: Account) -> Signal<[CallRecord], NoError> {
|
|
return account.viewTracker.callListView(type: .missed, index: MessageIndex.absoluteUpperBound(), count: 30)
|
|
|> take(1)
|
|
|> map { view -> [CallRecord] in
|
|
var calls: [CallRecord] = []
|
|
for entry in view.entries {
|
|
switch entry {
|
|
case let .message(_, messages):
|
|
for message in messages {
|
|
if let call = callWithTelegramMessage(message, account: account) {
|
|
calls.append(call)
|
|
}
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
return calls.sorted { $0.date.compare($1.date) == .orderedDescending }
|
|
}
|
|
}
|
|
|
|
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
|
|
private func callWithTelegramMessage(_ telegramMessage: Message, account: Account) -> CallRecord? {
|
|
guard let author = telegramMessage.author, let user = telegramMessage.peers[author.id] as? TelegramUser else {
|
|
return nil
|
|
}
|
|
|
|
let identifier = "\(telegramMessage.id.peerId.toInt64())_\(telegramMessage.id.namespace)_\(telegramMessage.id.id)"
|
|
let personHandle: INPersonHandle
|
|
if #available(iOSApplicationExtension 10.2, iOS 10.2, *) {
|
|
var type: INPersonHandleType
|
|
var label: INPersonHandleLabel?
|
|
if let username = user.username {
|
|
label = INPersonHandleLabel(rawValue: "@\(username)")
|
|
type = .unknown
|
|
} else if let phone = user.phone {
|
|
label = INPersonHandleLabel(rawValue: formatPhoneNumber(phone))
|
|
type = .phoneNumber
|
|
} else {
|
|
label = nil
|
|
type = .unknown
|
|
}
|
|
personHandle = INPersonHandle(value: user.phone ?? "", type: type, label: label)
|
|
} else {
|
|
personHandle = INPersonHandle(value: user.phone ?? "", type: .phoneNumber)
|
|
}
|
|
|
|
let caller = INPerson(personHandle: personHandle, nameComponents: nil, displayName: user.nameOrPhone, image: nil, contactIdentifier: nil, customIdentifier: "tg\(user.id.toInt64())")
|
|
let date = Date(timeIntervalSince1970: TimeInterval(telegramMessage.timestamp))
|
|
|
|
var duration: Int32?
|
|
for media in telegramMessage.media {
|
|
if let action = media as? TelegramMediaAction, case let .phoneCall(_, _, callDuration, _) = action.action {
|
|
duration = callDuration
|
|
}
|
|
}
|
|
|
|
return CallRecord(identifier: identifier, date: date, caller: caller, duration: duration, unseen: true)
|
|
}
|
|
|
|
@available(iOSApplicationExtension 10.0, iOS 10.0, *)
|
|
private func messageWithTelegramMessage(_ telegramMessage: Message) -> INMessage? {
|
|
guard let author = telegramMessage.author, let user = telegramMessage.peers[author.id] as? TelegramUser, user.id.id != 777000 else {
|
|
return nil
|
|
}
|
|
|
|
let identifier = "\(telegramMessage.id.peerId.toInt64())_\(telegramMessage.id.namespace)_\(telegramMessage.id.id)"
|
|
let personHandle: INPersonHandle
|
|
if #available(iOSApplicationExtension 10.2, iOS 10.2, *) {
|
|
var type: INPersonHandleType
|
|
var label: INPersonHandleLabel?
|
|
if let username = user.username {
|
|
label = INPersonHandleLabel(rawValue: "@\(username)")
|
|
type = .unknown
|
|
} else if let phone = user.phone {
|
|
label = INPersonHandleLabel(rawValue: formatPhoneNumber(phone))
|
|
type = .phoneNumber
|
|
} else {
|
|
label = nil
|
|
type = .unknown
|
|
}
|
|
personHandle = INPersonHandle(value: user.phone ?? "", type: type, label: label)
|
|
} else {
|
|
personHandle = INPersonHandle(value: user.phone ?? "", type: .phoneNumber)
|
|
}
|
|
|
|
let personIdentifier = "tg\(user.id.toInt64())"
|
|
let sender = INPerson(personHandle: personHandle, nameComponents: nil, displayName: user.nameOrPhone, image: nil, contactIdentifier: personIdentifier, customIdentifier: personIdentifier)
|
|
let date = Date(timeIntervalSince1970: TimeInterval(telegramMessage.timestamp))
|
|
|
|
let message: INMessage
|
|
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
|
var messageType: INMessageType = .text
|
|
loop: for media in telegramMessage.media {
|
|
if media is TelegramMediaImage {
|
|
messageType = .mediaImage
|
|
break loop
|
|
}
|
|
else if let file = media as? TelegramMediaFile {
|
|
if file.isVideo {
|
|
messageType = .mediaVideo
|
|
break loop
|
|
} else if file.isMusic {
|
|
messageType = .mediaAudio
|
|
break loop
|
|
} else if file.isVoice {
|
|
messageType = .mediaAudio
|
|
break loop
|
|
} else if file.isSticker || file.isAnimatedSticker {
|
|
messageType = .sticker
|
|
break loop
|
|
} else if file.isAnimated {
|
|
messageType = .mediaVideo
|
|
break loop
|
|
} else if #available(iOSApplicationExtension 12.0, iOS 12.0, *) {
|
|
messageType = .file
|
|
break loop
|
|
}
|
|
} else if media is TelegramMediaMap {
|
|
messageType = .mediaLocation
|
|
break loop
|
|
} else if media is TelegramMediaContact {
|
|
messageType = .mediaAddressCard
|
|
break loop
|
|
}
|
|
}
|
|
|
|
if telegramMessage.text.isEmpty && messageType == .text {
|
|
return nil
|
|
}
|
|
|
|
message = INMessage(identifier: identifier, conversationIdentifier: "\(telegramMessage.id.peerId.toInt64())", content: telegramMessage.text, dateSent: date, sender: sender, recipients: [], groupName: nil, messageType: messageType)
|
|
} else {
|
|
if telegramMessage.text.isEmpty {
|
|
return nil
|
|
}
|
|
message = INMessage(identifier: identifier, content: telegramMessage.text, dateSent: date, sender: sender, recipients: [])
|
|
}
|
|
|
|
return message
|
|
}
|