mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
CarPlay fixes
This commit is contained in:
parent
7b147bc8e1
commit
d748b3e881
@ -56,8 +56,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
let appBundleIdentifier = Bundle.main.bundleIdentifier!
|
||||
guard let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
||||
guard let appBundleIdentifier = Bundle.main.bundleIdentifier, let lastDotRange = appBundleIdentifier.range(of: ".", options: [.backwards]) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -98,30 +97,30 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
let encryptionParameters = ValueBoxEncryptionParameters(forceEncryptionIfNoSet: false, key: ValueBoxEncryptionParameters.Key(data: deviceSpecificEncryptionParameters.key)!, salt: ValueBoxEncryptionParameters.Salt(data: deviceSpecificEncryptionParameters.salt)!)
|
||||
|
||||
account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, appData: .single(buildConfig.bundleData(withAppToken: nil))), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: accountAuxiliaryMethods, encryptionParameters: encryptionParameters)
|
||||
|> mapToSignal { account -> Signal<Account?, NoError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
|> mapToSignal { account -> Signal<Account?, NoError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
case .upgrading:
|
||||
return .complete()
|
||||
case let .authorized(account):
|
||||
return applicationSettings(accountManager: accountManager)
|
||||
|> deliverOnMainQueue
|
||||
|> map { settings -> Account in
|
||||
accountCache = account
|
||||
Logger.shared.logToFile = settings.logging.logToFile
|
||||
Logger.shared.logToConsole = settings.logging.logToConsole
|
||||
|
||||
Logger.shared.redactSensitiveData = settings.logging.redactSensitiveData
|
||||
return account
|
||||
|> deliverOnMainQueue
|
||||
|> map { settings -> Account in
|
||||
accountCache = account
|
||||
Logger.shared.logToFile = settings.logging.logToFile
|
||||
Logger.shared.logToConsole = settings.logging.logToConsole
|
||||
|
||||
Logger.shared.redactSensitiveData = settings.logging.redactSensitiveData
|
||||
return account
|
||||
}
|
||||
case .unauthorized:
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
|> take(1)
|
||||
}
|
||||
|> take(1)
|
||||
}
|
||||
self.accountPromise.set(account)
|
||||
}
|
||||
@ -145,31 +144,31 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
@available(iOSApplicationExtension 11.0, *)
|
||||
var sendMessageRecipientResulutionResult: INSendMessageRecipientResolutionResult {
|
||||
switch self {
|
||||
case let .success(person):
|
||||
return .success(with: person)
|
||||
case let .disambiguation(persons):
|
||||
return .disambiguation(with: persons)
|
||||
case .needsValue:
|
||||
return .needsValue()
|
||||
case .noResult:
|
||||
return .unsupported()
|
||||
case .skip:
|
||||
return .notRequired()
|
||||
case let .success(person):
|
||||
return .success(with: person)
|
||||
case let .disambiguation(persons):
|
||||
return .disambiguation(with: persons)
|
||||
case .needsValue:
|
||||
return .needsValue()
|
||||
case .noResult:
|
||||
return .unsupported()
|
||||
case .skip:
|
||||
return .notRequired()
|
||||
}
|
||||
}
|
||||
|
||||
var personResolutionResult: INPersonResolutionResult {
|
||||
switch self {
|
||||
case let .success(person):
|
||||
return .success(with: person)
|
||||
case let .disambiguation(persons):
|
||||
return .disambiguation(with: persons)
|
||||
case .needsValue:
|
||||
return .needsValue()
|
||||
case .noResult:
|
||||
return .unsupported()
|
||||
case .skip:
|
||||
return .notRequired()
|
||||
case let .success(person):
|
||||
return .success(with: person)
|
||||
case let .disambiguation(persons):
|
||||
return .disambiguation(with: persons)
|
||||
case .needsValue:
|
||||
return .needsValue()
|
||||
case .noResult:
|
||||
return .unsupported()
|
||||
case .skip:
|
||||
return .notRequired()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,14 +236,14 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|> take(1)
|
||||
|> mapToSignal { matchedContacts in
|
||||
return account
|
||||
|> introduceError(IntentContactsError.self)
|
||||
|> mapToSignal { account -> Signal<[(String, TelegramUser)], IntentContactsError> in
|
||||
if let account = account {
|
||||
return matchingCloudContacts(postbox: account.postbox, contacts: matchedContacts)
|
||||
|> introduceError(IntentContactsError.self)
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|> introduceError(IntentContactsError.self)
|
||||
|> mapToSignal { account -> Signal<[(String, TelegramUser)], IntentContactsError> in
|
||||
if let account = account {
|
||||
return matchingCloudContacts(postbox: account.postbox, contacts: matchedContacts)
|
||||
|> introduceError(IntentContactsError.self)
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
self.resolvePersonsDisposable.set((signal
|
||||
@ -279,33 +278,33 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
let account = self.accountPromise.get()
|
||||
|
||||
let signal = account
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> mapToSignal { account -> Signal<INPerson?, IntentHandlingError> in
|
||||
if let account = account {
|
||||
return matchingCloudContact(postbox: account.postbox, peerId: PeerId(peerId))
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> map { user -> INPerson? in
|
||||
if let user = user {
|
||||
return personWithUser(stableId: "tg\(peerId)", user: user)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> mapToSignal { account -> Signal<INPerson?, IntentHandlingError> in
|
||||
if let account = account {
|
||||
return matchingCloudContact(postbox: account.postbox, peerId: PeerId(peerId))
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> map { user -> INPerson? in
|
||||
if let user = user {
|
||||
return personWithUser(stableId: "tg\(peerId)", user: user)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
} else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
|
||||
self.resolvePersonsDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { person in
|
||||
if let person = person {
|
||||
completion([INSendMessageRecipientResolutionResult.success(with: person)])
|
||||
} else {
|
||||
completion([INSendMessageRecipientResolutionResult.needsValue()])
|
||||
}
|
||||
}, error: { error in
|
||||
completion([INSendMessageRecipientResolutionResult.unsupported(forReason: .noAccount)])
|
||||
}))
|
||||
|> deliverOnMainQueue).start(next: { person in
|
||||
if let person = person {
|
||||
completion([INSendMessageRecipientResolutionResult.success(with: person)])
|
||||
} else {
|
||||
completion([INSendMessageRecipientResolutionResult.needsValue()])
|
||||
}
|
||||
}, error: { error in
|
||||
completion([INSendMessageRecipientResolutionResult.unsupported(forReason: .noAccount)])
|
||||
}))
|
||||
} else {
|
||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||
completion([INSendMessageRecipientResolutionResult.notRequired()])
|
||||
@ -342,48 +341,48 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
func handle(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> take(1)
|
||||
|> take(1)
|
||||
|> mapError { _ -> IntentHandlingError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { account -> Signal<Void, IntentHandlingError> in
|
||||
guard let account = account else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
guard let recipient = intent.recipients?.first, let customIdentifier = recipient.customIdentifier, customIdentifier.hasPrefix("tg") else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
guard let peerIdValue = Int64(String(customIdentifier[customIdentifier.index(customIdentifier.startIndex, offsetBy: 2)...])) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
let peerId = PeerId(peerIdValue)
|
||||
if peerId.namespace != Namespaces.Peer.CloudUser {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
account.shouldBeServiceTaskMaster.set(.single(.now))
|
||||
return standaloneSendMessage(account: account, peerId: peerId, text: intent.content ?? "", attributes: [], media: nil, replyToMessageId: nil)
|
||||
|> mapError { _ -> IntentHandlingError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { account -> Signal<Void, IntentHandlingError> in
|
||||
guard let account = account else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
guard let recipient = intent.recipients?.first, let customIdentifier = recipient.customIdentifier, customIdentifier.hasPrefix("tg") else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
guard let peerIdValue = Int64(String(customIdentifier[customIdentifier.index(customIdentifier.startIndex, offsetBy: 2)...])) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
let peerId = PeerId(peerIdValue)
|
||||
if peerId.namespace != Namespaces.Peer.CloudUser {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
account.shouldBeServiceTaskMaster.set(.single(.now))
|
||||
return standaloneSendMessage(account: account, peerId: peerId, text: intent.content ?? "", attributes: [], media: nil, replyToMessageId: nil)
|
||||
|> mapError { _ -> IntentHandlingError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, IntentHandlingError> in
|
||||
return .complete()
|
||||
}
|
||||
|> afterDisposed {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<Void, IntentHandlingError> in
|
||||
return .complete()
|
||||
}
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
|
||||
let response = INSendMessageIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}, completed: {
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
|
||||
let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
|> afterDisposed {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
|
||||
let response = INSendMessageIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}, completed: {
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
|
||||
let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
}
|
||||
|
||||
// MARK: - INSearchForMessagesIntentHandling
|
||||
@ -394,42 +393,48 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
func handle(intent: INSearchForMessagesIntent, completion: @escaping (INSearchForMessagesIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> take(1)
|
||||
|> take(1)
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> mapToSignal { account -> Signal<[INMessage], IntentHandlingError> in
|
||||
guard let account = account else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
account.shouldBeServiceTaskMaster.set(.single(.now))
|
||||
account.resetStateManagement()
|
||||
|
||||
let completion: Signal<Void, NoError> = account.stateManager.pollStateUpdateCompletion()
|
||||
|> map { _ in
|
||||
return Void()
|
||||
}
|
||||
|
||||
return (completion |> timeout(4.0, queue: Queue.mainQueue(), alternate: .single(Void())))
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> mapToSignal { account -> Signal<[INMessage], IntentHandlingError> in
|
||||
guard let account = account else {
|
||||
return .fail(.generic)
|
||||
|> take(1)
|
||||
|> mapToSignal { _ -> Signal<[INMessage], IntentHandlingError> in
|
||||
let messages: Signal<[INMessage], NoError>
|
||||
if let identifiers = intent.identifiers, !identifiers.isEmpty {
|
||||
messages = getMessages(account: account, ids: identifiers.compactMap(MessageId.init(string:)))
|
||||
} else {
|
||||
messages = unreadMessages(account: account)
|
||||
}
|
||||
|
||||
account.shouldBeServiceTaskMaster.set(.single(.now))
|
||||
account.resetStateManagement()
|
||||
|
||||
let completion: Signal<Void, NoError> = account.stateManager.pollStateUpdateCompletion()
|
||||
|> map { _ in
|
||||
return Void()
|
||||
}
|
||||
|
||||
return (completion |> timeout(4.0, queue: Queue.mainQueue(), alternate: .single(Void())))
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> take(1)
|
||||
|> mapToSignal { _ -> Signal<[INMessage], IntentHandlingError> in
|
||||
return unreadMessages(account: account)
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> afterDisposed {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
return messages
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> afterDisposed {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { messages in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchForMessagesIntent.self))
|
||||
let response = INSearchForMessagesIntentResponse(code: .success, userActivity: userActivity)
|
||||
response.messages = messages
|
||||
completion(response)
|
||||
}, error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchForMessagesIntent.self))
|
||||
let response = INSearchForMessagesIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { messages in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchForMessagesIntent.self))
|
||||
let response = INSearchForMessagesIntentResponse(code: .success, userActivity: userActivity)
|
||||
response.messages = messages
|
||||
completion(response)
|
||||
}, error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchForMessagesIntent.self))
|
||||
let response = INSearchForMessagesIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
}
|
||||
|
||||
// MARK: - INSetMessageAttributeIntentHandling
|
||||
@ -449,61 +454,61 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
func handle(intent: INSetMessageAttributeIntent, completion: @escaping (INSetMessageAttributeIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> take(1)
|
||||
|> mapError { _ -> IntentHandlingError in
|
||||
return .generic
|
||||
|> take(1)
|
||||
|> mapError { _ -> IntentHandlingError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { account -> Signal<Void, IntentHandlingError> in
|
||||
guard let account = account else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|> mapToSignal { account -> Signal<Void, IntentHandlingError> in
|
||||
guard let account = account else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
var signals: [Signal<Void, IntentHandlingError>] = []
|
||||
var maxMessageIdsToApply: [PeerId: MessageId] = [:]
|
||||
if let identifiers = intent.identifiers {
|
||||
for identifier in identifiers {
|
||||
let components = identifier.components(separatedBy: "_")
|
||||
if let first = components.first, let peerId = Int64(first), let namespace = Int32(components[1]), let id = Int32(components[2]) {
|
||||
let peerId = PeerId(peerId)
|
||||
let messageId = MessageId(peerId: peerId, namespace: namespace, id: id)
|
||||
if let currentMessageId = maxMessageIdsToApply[peerId] {
|
||||
if currentMessageId < messageId {
|
||||
maxMessageIdsToApply[peerId] = messageId
|
||||
}
|
||||
} else {
|
||||
|
||||
var signals: [Signal<Void, IntentHandlingError>] = []
|
||||
var maxMessageIdsToApply: [PeerId: MessageId] = [:]
|
||||
if let identifiers = intent.identifiers {
|
||||
for identifier in identifiers {
|
||||
let components = identifier.components(separatedBy: "_")
|
||||
if let first = components.first, let peerId = Int64(first), let namespace = Int32(components[1]), let id = Int32(components[2]) {
|
||||
let peerId = PeerId(peerId)
|
||||
let messageId = MessageId(peerId: peerId, namespace: namespace, id: id)
|
||||
if let currentMessageId = maxMessageIdsToApply[peerId] {
|
||||
if currentMessageId < messageId {
|
||||
maxMessageIdsToApply[peerId] = messageId
|
||||
}
|
||||
} else {
|
||||
maxMessageIdsToApply[peerId] = messageId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (_, messageId) in maxMessageIdsToApply {
|
||||
signals.append(applyMaxReadIndexInteractively(postbox: account.postbox, stateManager: account.stateManager, index: MessageIndex(id: messageId, timestamp: 0))
|
||||
|> introduceError(IntentHandlingError.self))
|
||||
}
|
||||
|
||||
if signals.isEmpty {
|
||||
return .complete()
|
||||
} else {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.now))
|
||||
return combineLatest(signals)
|
||||
|> mapToSignal { _ -> Signal<Void, IntentHandlingError> in
|
||||
return .complete()
|
||||
}
|
||||
|> afterDisposed {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSetMessageAttributeIntent.self))
|
||||
let response = INSetMessageAttributeIntentResponse(code: .failure, userActivity: userActivity)
|
||||
completion(response)
|
||||
}, completed: {
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSetMessageAttributeIntent.self))
|
||||
let response = INSetMessageAttributeIntentResponse(code: .success, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
|
||||
for (_, messageId) in maxMessageIdsToApply {
|
||||
signals.append(applyMaxReadIndexInteractively(postbox: account.postbox, stateManager: account.stateManager, index: MessageIndex(id: messageId, timestamp: 0))
|
||||
|> introduceError(IntentHandlingError.self))
|
||||
}
|
||||
|
||||
if signals.isEmpty {
|
||||
return .complete()
|
||||
} else {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.now))
|
||||
return combineLatest(signals)
|
||||
|> mapToSignal { _ -> Signal<Void, IntentHandlingError> in
|
||||
return .complete()
|
||||
}
|
||||
|> afterDisposed {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSetMessageAttributeIntent.self))
|
||||
let response = INSetMessageAttributeIntentResponse(code: .failure, userActivity: userActivity)
|
||||
completion(response)
|
||||
}, completed: {
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSetMessageAttributeIntent.self))
|
||||
let response = INSetMessageAttributeIntentResponse(code: .success, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
}
|
||||
|
||||
// MARK: - INStartAudioCallIntentHandling
|
||||
@ -520,36 +525,36 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
func handle(intent: INStartAudioCallIntent, completion: @escaping (INStartAudioCallIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> take(1)
|
||||
|> mapError { _ -> IntentHandlingError in
|
||||
return .generic
|
||||
|> take(1)
|
||||
|> mapError { _ -> IntentHandlingError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { account -> Signal<PeerId, IntentHandlingError> in
|
||||
guard let contact = intent.contacts?.first, let customIdentifier = contact.customIdentifier, customIdentifier.hasPrefix("tg") else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|> mapToSignal { account -> Signal<PeerId, IntentHandlingError> in
|
||||
guard let contact = intent.contacts?.first, let customIdentifier = contact.customIdentifier, customIdentifier.hasPrefix("tg") else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
guard let peerIdValue = Int64(String(customIdentifier[customIdentifier.index(customIdentifier.startIndex, offsetBy: 2)...])) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
let peerId = PeerId(peerIdValue)
|
||||
if peerId.namespace != Namespaces.Peer.CloudUser {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
return .single(peerId)
|
||||
|
||||
guard let peerIdValue = Int64(String(customIdentifier[customIdentifier.index(customIdentifier.startIndex, offsetBy: 2)...])) else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { peerId in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INStartAudioCallIntent.self))
|
||||
userActivity.userInfo = ["handle": "TGCA\(peerId.toInt64())"]
|
||||
let response = INStartAudioCallIntentResponse(code: .continueInApp, userActivity: userActivity)
|
||||
completion(response)
|
||||
}, error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INStartAudioCallIntent.self))
|
||||
let response = INStartAudioCallIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
|
||||
let peerId = PeerId(peerIdValue)
|
||||
if peerId.namespace != Namespaces.Peer.CloudUser {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
return .single(peerId)
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { peerId in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INStartAudioCallIntent.self))
|
||||
userActivity.userInfo = ["handle": "TGCA\(peerId.toInt64())"]
|
||||
let response = INStartAudioCallIntentResponse(code: .continueInApp, userActivity: userActivity)
|
||||
completion(response)
|
||||
}, error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INStartAudioCallIntent.self))
|
||||
let response = INStartAudioCallIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
}
|
||||
|
||||
// MARK: - INSearchCallHistoryIntentHandling
|
||||
@ -565,34 +570,34 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
func handle(intent: INSearchCallHistoryIntent, completion: @escaping (INSearchCallHistoryIntentResponse) -> Void) {
|
||||
self.actionDisposable.set((self.accountPromise.get()
|
||||
|> take(1)
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> mapToSignal { account -> Signal<[CallRecord], IntentHandlingError> in
|
||||
guard let account = account else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
account.shouldBeServiceTaskMaster.set(.single(.now))
|
||||
return missedCalls(account: account)
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> afterDisposed {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
|> take(1)
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> mapToSignal { account -> Signal<[CallRecord], IntentHandlingError> in
|
||||
guard let account = account else {
|
||||
return .fail(.generic)
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { calls in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchCallHistoryIntent.self))
|
||||
let response: INSearchCallHistoryIntentResponse
|
||||
if #available(iOSApplicationExtension 11.0, *) {
|
||||
response = INSearchCallHistoryIntentResponse(code: .success, userActivity: userActivity)
|
||||
response.callRecords = calls.map { $0.intentCall }
|
||||
} else {
|
||||
response = INSearchCallHistoryIntentResponse(code: .continueInApp, userActivity: userActivity)
|
||||
}
|
||||
completion(response)
|
||||
}, error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchCallHistoryIntent.self))
|
||||
let response = INSearchCallHistoryIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
|
||||
account.shouldBeServiceTaskMaster.set(.single(.now))
|
||||
return missedCalls(account: account)
|
||||
|> introduceError(IntentHandlingError.self)
|
||||
|> afterDisposed {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { calls in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchCallHistoryIntent.self))
|
||||
let response: INSearchCallHistoryIntentResponse
|
||||
if #available(iOSApplicationExtension 11.0, *) {
|
||||
response = INSearchCallHistoryIntentResponse(code: .success, userActivity: userActivity)
|
||||
response.callRecords = calls.map { $0.intentCall }
|
||||
} else {
|
||||
response = INSearchCallHistoryIntentResponse(code: .continueInApp, userActivity: userActivity)
|
||||
}
|
||||
completion(response)
|
||||
}, error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchCallHistoryIntent.self))
|
||||
let response = INSearchCallHistoryIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,33 @@
|
||||
import Foundation
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
|
||||
return account.postbox.tailChatListView(groupId: .root, count: 20, summaryComponents: ChatListEntrySummaryComponents())
|
||||
|> take(1)
|
||||
@ -42,7 +64,7 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
|
||||
}
|
||||
|
||||
if !isRead {
|
||||
if let message = messageWithTelegramMessage(entry.message, account: account) {
|
||||
if let message = messageWithTelegramMessage(entry.message) {
|
||||
messages.append(message)
|
||||
}
|
||||
}
|
||||
@ -58,7 +80,7 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
|
||||
} else {
|
||||
return combineLatest(signals)
|
||||
|> map { results -> [INMessage] in
|
||||
return results.flatMap { $0 }.sorted(by: { $0.dateSent!.compare($1.dateSent!) == ComparisonResult.orderedDescending })
|
||||
return results.flatMap { $0 }.sorted { $0.dateSent!.compare($1.dateSent!) == .orderedDescending }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,7 +116,7 @@ func missedCalls(account: Account) -> Signal<[CallRecord], NoError> {
|
||||
break
|
||||
}
|
||||
}
|
||||
return calls.sorted(by: { $0.date.compare($1.date) == ComparisonResult.orderedDescending })
|
||||
return calls.sorted { $0.date.compare($1.date) == .orderedDescending }
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,7 +158,7 @@ private func callWithTelegramMessage(_ telegramMessage: Message, account: Accoun
|
||||
return CallRecord(identifier: identifier, date: date, caller: caller, duration: duration, unseen: true)
|
||||
}
|
||||
|
||||
private func messageWithTelegramMessage(_ telegramMessage: Message, account: Account) -> INMessage? {
|
||||
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
|
||||
}
|
||||
@ -181,7 +203,7 @@ private func messageWithTelegramMessage(_ telegramMessage: Message, account: Acc
|
||||
messageType = .mediaAudio
|
||||
break loop
|
||||
} else if file.isVoice {
|
||||
messageType = .audio
|
||||
messageType = .mediaAudio
|
||||
break loop
|
||||
} else if file.isSticker || file.isAnimatedSticker {
|
||||
messageType = .sticker
|
||||
@ -189,6 +211,9 @@ private func messageWithTelegramMessage(_ telegramMessage: Message, account: Acc
|
||||
} else if file.isAnimated {
|
||||
messageType = .mediaVideo
|
||||
break loop
|
||||
} else if #available(iOSApplicationExtension 12.0, *) {
|
||||
messageType = .file
|
||||
break loop
|
||||
}
|
||||
} else if media is TelegramMediaMap {
|
||||
messageType = .mediaLocation
|
||||
|
@ -33,7 +33,7 @@
|
||||
<string>merchant.privatbank.test.telergramios</string>
|
||||
<string>merchant.privatbank.prod.telergram</string>
|
||||
</array>
|
||||
<key>com.apple.developer.carplay-messaging</key><true/>
|
||||
<key>com.apple.developer.carplay-calling</key><true/>
|
||||
<key>com.apple.developer.carplay-messaging</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -97,7 +97,7 @@ public func searchStickers(account: Account, query: String, scope: SearchSticker
|
||||
for entry in transaction.getOrderedListItems(collectionId: Namespaces.OrderedItemList.CloudSavedStickers) {
|
||||
if let item = entry.contents as? SavedStickerItem {
|
||||
for representation in item.stringRepresentations {
|
||||
if representation == query {
|
||||
if representation.hasPrefix(query) {
|
||||
result.append(FoundStickerItem(file: item.file, stringRepresentations: item.stringRepresentations))
|
||||
break
|
||||
}
|
||||
@ -115,7 +115,7 @@ public func searchStickers(account: Account, query: String, scope: SearchSticker
|
||||
if let item = entry.contents as? RecentMediaItem, let file = item.media as? TelegramMediaFile {
|
||||
if !currentItems.contains(file.fileId) {
|
||||
for case let .Sticker(sticker) in file.attributes {
|
||||
if sticker.displayText == query {
|
||||
if sticker.displayText.hasPrefix(query) {
|
||||
matchingRecentItemsIds.insert(file.fileId)
|
||||
}
|
||||
recentItemsIds.insert(file.fileId)
|
||||
@ -130,9 +130,14 @@ public func searchStickers(account: Account, query: String, scope: SearchSticker
|
||||
}
|
||||
}
|
||||
|
||||
var searchQuery: ItemCollectionSearchQuery = .exact(ValueBoxKey(query))
|
||||
if query == "\u{2764}" {
|
||||
searchQuery = .matching([ValueBoxKey("\u{2764}"), ValueBoxKey("\u{2764}\u{fe0f}")])
|
||||
}
|
||||
|
||||
var installedItems: [FoundStickerItem] = []
|
||||
var installedAnimatedItems: [FoundStickerItem] = []
|
||||
for item in transaction.searchItemCollection(namespace: Namespaces.ItemCollection.CloudStickerPacks, query: .exact(ValueBoxKey(query))) {
|
||||
for item in transaction.searchItemCollection(namespace: Namespaces.ItemCollection.CloudStickerPacks, query: searchQuery) {
|
||||
if let item = item as? StickerPackItem {
|
||||
if !currentItems.contains(item.file.fileId) {
|
||||
var stringRepresentations: [String] = []
|
||||
|
Loading…
x
Reference in New Issue
Block a user