mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-25 20:50:47 +00:00
Merge commit '42673dc7f0ba37737573aa5ad95df3d916a57ceb'
This commit is contained in:
commit
74943cd1b4
@ -12,13 +12,17 @@ struct MatchingDeviceContact {
|
||||
let phoneNumbers: [String]
|
||||
}
|
||||
|
||||
func matchingDeviceContacts(stableIds: [String]) -> Signal<[MatchingDeviceContact], NoError> {
|
||||
enum IntentContactsError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func matchingDeviceContacts(stableIds: [String]) -> Signal<[MatchingDeviceContact], IntentContactsError> {
|
||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||
return .single([])
|
||||
return .fail(.generic)
|
||||
}
|
||||
let store = CNContactStore()
|
||||
guard let contacts = try? store.unifiedContacts(matching: CNContact.predicateForContacts(withIdentifiers: stableIds), keysToFetch: [CNContactFormatter.descriptorForRequiredKeys(for: .fullName), CNContactPhoneNumbersKey as CNKeyDescriptor]) else {
|
||||
return .single([])
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
||||
return .single(contacts.map({ contact in
|
||||
@ -34,19 +38,58 @@ func matchingDeviceContacts(stableIds: [String]) -> Signal<[MatchingDeviceContac
|
||||
}))
|
||||
}
|
||||
|
||||
private func matchPhoneNumbers(_ lhs: String, _ rhs: String) -> Bool {
|
||||
if lhs.count < 10 && lhs.count == rhs.count {
|
||||
return lhs == rhs
|
||||
} else if lhs.count >= 10 && rhs.count >= 10 && lhs.suffix(10) == rhs.suffix(10) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func matchingCloudContacts(postbox: Postbox, contacts: [MatchingDeviceContact]) -> Signal<[(String, TelegramUser)], NoError> {
|
||||
return postbox.transaction { transaction -> [(String, TelegramUser)] in
|
||||
var result: [(String, TelegramUser)] = []
|
||||
outer: for peerId in transaction.getContactPeerIds() {
|
||||
if let peer = transaction.getPeer(peerId) as? TelegramUser, let phone = peer.phone {
|
||||
if let peer = transaction.getPeer(peerId) as? TelegramUser, let peerPhoneNumber = peer.phone {
|
||||
for contact in contacts {
|
||||
for phoneNumber in contact.phoneNumbers {
|
||||
if arePhoneNumbersEqual(phoneNumber, phone) {
|
||||
if matchPhoneNumbers(phoneNumber, peerPhoneNumber) {
|
||||
result.append((contact.stableId, peer))
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
}
|
||||
// var parsedPhoneNumbers: [String: ParsedPhoneNumber] = [:]
|
||||
// let parsedPeerPhoneNumber: ParsedPhoneNumber?
|
||||
// if let number = parsedPhoneNumbers[peerPhoneNumber] {
|
||||
// parsedPeerPhoneNumber = number
|
||||
// } else if let number = ParsedPhoneNumber(string: peerPhoneNumber) {
|
||||
// parsedPeerPhoneNumber = number
|
||||
// parsedPhoneNumbers[peerPhoneNumber] = number
|
||||
// } else {
|
||||
// parsedPeerPhoneNumber = nil
|
||||
// }
|
||||
//
|
||||
// for contact in contacts {
|
||||
// for phoneNumber in contact.phoneNumbers {
|
||||
// let parsedPhoneNumber: ParsedPhoneNumber?
|
||||
// if let number = parsedPhoneNumbers[phoneNumber] {
|
||||
// parsedPhoneNumber = number
|
||||
// } else if let number = ParsedPhoneNumber(string: phoneNumber) {
|
||||
// parsedPhoneNumber = number
|
||||
// parsedPhoneNumbers[phoneNumber] = number
|
||||
// } else {
|
||||
// parsedPhoneNumber = nil
|
||||
// }
|
||||
//
|
||||
// if parsedPeerPhoneNumber == parsedPhoneNumber {
|
||||
// result.append((contact.stableId, peer))
|
||||
// continue outer
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
@ -4,6 +4,7 @@ import TelegramCore
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
import BuildConfig
|
||||
import Contacts
|
||||
|
||||
private var accountCache: Account?
|
||||
|
||||
@ -47,7 +48,7 @@ enum IntentHandlingError {
|
||||
}
|
||||
|
||||
class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessagesIntentHandling, INSetMessageAttributeIntentHandling, INStartAudioCallIntentHandling, INSearchCallHistoryIntentHandling {
|
||||
private let accountPromise = Promise<Account>()
|
||||
private let accountPromise = Promise<Account?>()
|
||||
|
||||
private let resolvePersonsDisposable = MetaDisposable()
|
||||
private let actionDisposable = MetaDisposable()
|
||||
@ -86,7 +87,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
let appVersion = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String) ?? "unknown"
|
||||
|
||||
let account: Signal<Account, NoError>
|
||||
let account: Signal<Account?, NoError>
|
||||
if let accountCache = accountCache {
|
||||
account = .single(accountCache)
|
||||
} else {
|
||||
@ -97,7 +98,7 @@ 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
|
||||
|> mapToSignal { account -> Signal<Account?, NoError> in
|
||||
if let account = account {
|
||||
switch account {
|
||||
case .upgrading:
|
||||
@ -117,12 +118,9 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
return .complete()
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
|> afterNext { account in
|
||||
account.resetStateManagement()
|
||||
}
|
||||
|> take(1)
|
||||
}
|
||||
self.accountPromise.set(account)
|
||||
@ -138,6 +136,11 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
}
|
||||
|
||||
private func resolve(persons: [INPerson]?, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
|
||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||
completion([INPersonResolutionResult.notRequired()])
|
||||
return
|
||||
}
|
||||
|
||||
guard let initialPersons = persons, !initialPersons.isEmpty else {
|
||||
completion([INPersonResolutionResult.needsValue()])
|
||||
return
|
||||
@ -205,8 +208,14 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|> take(1)
|
||||
|> mapToSignal { matchedContacts in
|
||||
return account
|
||||
|> mapToSignal { account in
|
||||
return matchingCloudContacts(postbox: account.postbox, contacts: matchedContacts)
|
||||
|> 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
|
||||
@ -219,6 +228,8 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
return INPersonResolutionResult.success(with: person)
|
||||
})
|
||||
}
|
||||
}, error: { error in
|
||||
completion([INPersonResolutionResult.unsupported()])
|
||||
}))
|
||||
}
|
||||
|
||||
@ -230,14 +241,20 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
let account = self.accountPromise.get()
|
||||
|
||||
let signal = account
|
||||
|> mapToSignal { account -> Signal<INPerson?, NoError> in
|
||||
return matchingCloudContact(postbox: account.postbox, peerId: PeerId(peerId))
|
||||
|> 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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,6 +265,8 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
} else {
|
||||
completion([INPersonResolutionResult.needsValue()])
|
||||
}
|
||||
}, error: { error in
|
||||
completion([INPersonResolutionResult.notRequired()])
|
||||
}))
|
||||
} else {
|
||||
self.resolve(persons: intent.recipients, with: completion)
|
||||
@ -258,6 +277,10 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
}
|
||||
|
||||
func resolveContent(for intent: INSendMessageIntent, with completion: @escaping (INStringResolutionResult) -> Void) {
|
||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||
completion(INStringResolutionResult.notRequired())
|
||||
return
|
||||
}
|
||||
if let text = intent.content, !text.isEmpty {
|
||||
completion(INStringResolutionResult.success(with: text))
|
||||
} else {
|
||||
@ -267,6 +290,11 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|
||||
func confirm(intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
|
||||
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
|
||||
let response = INSendMessageIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
return
|
||||
}
|
||||
let response = INSendMessageIntentResponse(code: .ready, userActivity: userActivity)
|
||||
completion(response)
|
||||
}
|
||||
@ -278,6 +306,9 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
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)
|
||||
}
|
||||
@ -305,7 +336,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
}
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
|
||||
let response = INSendMessageIntentResponse(code: .failure, userActivity: userActivity)
|
||||
let response = INSendMessageIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}, completed: {
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
|
||||
@ -325,18 +356,27 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|> 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()
|
||||
|
||||
return account.stateManager.pollStateUpdateCompletion()
|
||||
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))
|
||||
|> afterDisposed {
|
||||
account.shouldBeServiceTaskMaster.set(.single(.never))
|
||||
}
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { messages in
|
||||
@ -346,7 +386,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
completion(response)
|
||||
}, error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchForMessagesIntent.self))
|
||||
let response = INSearchForMessagesIntentResponse(code: .failure, userActivity: userActivity)
|
||||
let response = INSearchForMessagesIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
}
|
||||
@ -373,8 +413,11 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { account -> Signal<Void, IntentHandlingError> in
|
||||
var signals: [Signal<Void, IntentHandlingError>] = []
|
||||
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 {
|
||||
@ -478,6 +521,10 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
|> 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)
|
||||
@ -497,7 +544,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
|
||||
completion(response)
|
||||
}, error: { _ in
|
||||
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSearchCallHistoryIntent.self))
|
||||
let response = INSearchCallHistoryIntentResponse(code: .failure, userActivity: userActivity)
|
||||
let response = INSearchCallHistoryIntentResponse(code: .failureRequiringAppLaunch, userActivity: userActivity)
|
||||
completion(response)
|
||||
}))
|
||||
}
|
||||
|
@ -13,6 +13,10 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
|
||||
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 {
|
||||
@ -133,7 +137,7 @@ private func callWithTelegramMessage(_ telegramMessage: Message, account: Accoun
|
||||
}
|
||||
|
||||
private func messageWithTelegramMessage(_ telegramMessage: Message, account: Account) -> INMessage? {
|
||||
guard let author = telegramMessage.author, let user = telegramMessage.peers[author.id] as? TelegramUser else {
|
||||
guard let author = telegramMessage.author, let user = telegramMessage.peers[author.id] as? TelegramUser, user.id.id != 777000 else {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -194,9 +198,16 @@ private func messageWithTelegramMessage(_ telegramMessage: Message, account: Acc
|
||||
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: [])
|
||||
}
|
||||
|
||||
|
@ -1304,7 +1304,10 @@ public class Account {
|
||||
self.managedOperationsDisposable.add(managedPendingPeerNotificationSettings(postbox: self.postbox, network: self.network).start())
|
||||
self.managedOperationsDisposable.add(managedSynchronizeAppLogEventsOperations(postbox: self.postbox, network: self.network).start())
|
||||
self.managedOperationsDisposable.add(managedNotificationSettingsBehaviors(postbox: self.postbox).start())
|
||||
self.managedOperationsDisposable.add(managedAnimatedEmojiUpdates(postbox: self.postbox, network: self.network).start())
|
||||
|
||||
if !self.supplementary {
|
||||
self.managedOperationsDisposable.add(managedAnimatedEmojiUpdates(postbox: self.postbox, network: self.network).start())
|
||||
}
|
||||
|
||||
let mediaBox = postbox.mediaBox
|
||||
self.storageSettingsDisposable = accountManager.sharedData(keys: [SharedDataKeys.cacheStorageSettings]).start(next: { [weak mediaBox] sharedData in
|
||||
|
@ -16,11 +16,27 @@ public func isViablePhoneNumber(_ string: String) -> Bool {
|
||||
return phoneNumberUtil.isViablePhoneNumber(string)
|
||||
}
|
||||
|
||||
public func arePhoneNumbersEqual(_ lhs: String, _ rhs: String) -> Bool {
|
||||
let result = phoneNumberUtil.isNumberMatch(lhs as NSString, second: rhs as NSString, error: nil)
|
||||
if result != .NO_MATCH && result != .NOT_A_NUMBER {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
public class ParsedPhoneNumber: Equatable {
|
||||
let rawPhoneNumber: NBPhoneNumber?
|
||||
|
||||
public init?(string: String) {
|
||||
if let number = try? phoneNumberUtil.parse(string, defaultRegion: NB_UNKNOWN_REGION) {
|
||||
self.rawPhoneNumber = number
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public static func == (lhs: ParsedPhoneNumber, rhs: ParsedPhoneNumber) -> Bool {
|
||||
var error: NSError?
|
||||
let result = phoneNumberUtil.isNumberMatch(lhs.rawPhoneNumber, second: rhs.rawPhoneNumber, error: &error)
|
||||
if error != nil {
|
||||
return false
|
||||
}
|
||||
if result != .NO_MATCH && result != .NOT_A_NUMBER {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -679,12 +679,12 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|
||||
hapticFeedback.impact(.heavy)
|
||||
Queue.mainQueue().after(0.2) {
|
||||
hapticFeedback.impact(.medium)
|
||||
Queue.mainQueue().after(0.74) {
|
||||
hapticFeedback.impact(.medium)
|
||||
Queue.mainQueue().after(0.78) {
|
||||
hapticFeedback.impact(.heavy)
|
||||
Queue.mainQueue().after(0.2) {
|
||||
hapticFeedback.impact(.medium)
|
||||
Queue.mainQueue().after(0.74) {
|
||||
hapticFeedback.impact(.medium)
|
||||
Queue.mainQueue().after(0.78) {
|
||||
hapticFeedback.impact(.heavy)
|
||||
Queue.mainQueue().after(0.2) {
|
||||
hapticFeedback.impact(.medium)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user