Files
ghostgram/submodules/TelegramIntents/Sources/TelegramIntents.swift

228 lines
11 KiB
Swift

import Foundation
import UIKit
import Intents
import Display
import Postbox
import TelegramCore
import SwiftSignalKit
import TelegramUIPreferences
import TelegramPresentationData
import AvatarNode
import AccountContext
private let savedMessagesAvatar: UIImage = {
return generateImage(CGSize(width: 60.0, height: 60.0), rotatedContext: { size, context in
var locations: [CGFloat] = [1.0, 0.0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: [UIColor(rgb: 0x2a9ef1).cgColor, UIColor(rgb: 0x72d5fd).cgColor] as CFArray, locations: &locations)!
context.drawLinearGradient(gradient, start: CGPoint(), end: CGPoint(x: 0.0, y: size.height), options: CGGradientDrawingOptions())
let factor = size.width / 60.0
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context.scaleBy(x: factor, y: -factor)
context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
if let savedMessagesIcon = generateTintedImage(image: UIImage(bundleImageName: "Avatar/SavedMessagesIcon"), color: .white) {
context.draw(savedMessagesIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((size.width - savedMessagesIcon.size.width) / 2.0), y: floor((size.height - savedMessagesIcon.size.height) / 2.0)), size: savedMessagesIcon.size))
}
})!
}()
public enum SendMessageIntentContext {
case chat
case share
}
public enum SendMessageIntentSubject: CaseIterable {
case contact
case savedMessages
case privateChat
case group
func toString() -> String {
switch self {
case .contact:
return "contact"
case .savedMessages:
return "savedMessages"
case .privateChat:
return "privateChat"
case .group:
return "group"
}
}
}
public func donateSendMessageIntent(account: Account, sharedContext: SharedAccountContext, intentContext: SendMessageIntentContext, peerIds: [PeerId]) {
if #available(iOSApplicationExtension 13.2, iOS 13.2, *) {
let _ = (sharedContext.accountManager.transaction { transaction -> Bool in
if case .none = transaction.getAccessChallengeData() {
return true
} else {
return false
}
}
|> mapToSignal { unlocked -> Signal<[(Peer, SendMessageIntentSubject, UIImage?)], NoError> in
if unlocked {
return sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.intentsSettings])
|> take(1)
|> mapToSignal { sharedData -> Signal<[(Peer, SendMessageIntentSubject)], NoError> in
let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.intentsSettings]?.get(IntentsSettings.self) ?? IntentsSettings.defaultSettings
if let accountId = settings.account, accountId != account.peerId {
return .single([])
}
if case .chat = intentContext, settings.onlyShared {
return .single([])
}
return TelegramEngine(account: account).data.get(
EngineDataMap(peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init)),
EngineDataMap(peerIds.map(TelegramEngine.EngineData.Item.Peer.IsContact.init)),
EngineDataMap(peerIds.map(TelegramEngine.EngineData.Item.Messages.ChatListGroup.init))
)
|> map { peerMap, isContactMap, chatListGroupMap -> [(Peer, SendMessageIntentSubject)] in
var peers: [(Peer, SendMessageIntentSubject)] = []
for peerId in peerIds {
if peerId.namespace != Namespaces.Peer.SecretChat, let maybePeer = peerMap[peerId], let peer = maybePeer {
var subject: SendMessageIntentSubject?
let chatListGroup = chatListGroupMap[peerId]
if chatListGroup == .archive {
continue
}
if peerId.namespace == Namespaces.Peer.CloudUser {
if peerId == account.peerId {
if !settings.savedMessages {
continue
}
subject = .savedMessages
} else if let isContact = isContactMap[peerId], isContact {
if !settings.contacts {
continue
}
subject = .contact
} else {
if !settings.privateChats {
continue
}
subject = .privateChat
}
} else if peerId.namespace == Namespaces.Peer.CloudGroup {
if !settings.groups {
continue
}
subject = .group
} else if case let .channel(peer) = peer {
if case .group = peer.info {
if !settings.groups {
continue
}
subject = .group
} else {
continue
}
} else {
continue
}
if let subject = subject {
peers.append((peer._asPeer(), subject))
}
}
}
return peers
}
}
|> mapToSignal { peers -> Signal<[(Peer, SendMessageIntentSubject, UIImage?)], NoError> in
var signals: [Signal<(Peer, SendMessageIntentSubject, UIImage?), NoError>] = []
for (peer, subject) in peers {
if peer.id == account.peerId {
signals.append(.single((peer, subject, savedMessagesAvatar)))
} else {
let peerAndAvatar = (peerAvatarImage(account: account, peerReference: PeerReference(peer), authorOfMessage: nil, representation: peer.smallProfileImage, clipStyle: .none) ?? .single(nil))
|> map { imageVersions -> (Peer, SendMessageIntentSubject, UIImage?) in
var avatarImage: UIImage?
if let image = imageVersions?.0 {
avatarImage = image
} else {
let avatarFont = avatarPlaceholderFont(size: 26.0)
let size = CGSize(width: 60.0, height: 60.0)
if let image = generateImage(size, rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
drawPeerAvatarLetters(context: context, size: CGSize(width: size.width, height: size.height), font: avatarFont, letters: peer.displayLetters, peerId: peer.id, nameColor: peer.nameColor)
})?.withRenderingMode(.alwaysOriginal) {
avatarImage = image
}
}
return (peer, subject, avatarImage)
}
signals.append(peerAndAvatar)
}
}
return combineLatest(signals)
}
} else {
return .single([])
}
}
|> deliverOnMainQueue).start(next: { peers in
let presentationData = sharedContext.currentPresentationData.with { $0 }
for (peer, _, avatarImage) in peers {
let recipientHandle = INPersonHandle(value: "tg\(peer.id.toInt64())", type: .unknown)
let displayTitle: String
var nameComponents = PersonNameComponents()
if let peer = peer as? TelegramUser {
if peer.botInfo != nil || peer.flags.contains(.isSupport) {
continue
}
if peer.id == account.peerId {
displayTitle = presentationData.strings.DialogList_SavedMessages
nameComponents.givenName = displayTitle
} else {
displayTitle = EnginePeer(peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
nameComponents.givenName = peer.firstName
nameComponents.familyName = peer.lastName
}
} else {
displayTitle = EnginePeer(peer).compactDisplayTitle
nameComponents.givenName = displayTitle
}
var personImage: INImage?
if let avatarImage = avatarImage, let avatarImageData = avatarImage.jpegData(compressionQuality: 0.8) {
personImage = INImage(imageData: avatarImageData)
}
let recipient = INPerson(personHandle: recipientHandle, nameComponents: nameComponents, displayName: displayTitle, image: personImage, contactIdentifier: nil, customIdentifier: "tg\(peer.id.toInt64())")
let intent = INSendMessageIntent(recipients: [recipient], content: nil, speakableGroupName: INSpeakableString(spokenPhrase: displayTitle), conversationIdentifier: "tg\(peer.id.toInt64())", serviceName: nil, sender: nil)
let interaction = INInteraction(intent: intent, response: nil)
interaction.direction = .outgoing
interaction.groupIdentifier = "sendMessage_\(peer.id.toInt64())"
interaction.donate { error in
if let error = error {
print(error)
}
}
}
})
}
}
public func deleteSendMessageIntents(peerId: PeerId) {
if #available(iOS 10.0, *) {
INInteraction.delete(with: "sendMessage_\(peerId.toInt64())")
}
}
public func deleteAllSendMessageIntents() {
if #available(iOS 10.0, *) {
INInteraction.deleteAll()
}
}