Merge commit 'd1bcfbc670080b90e187aa42075670febd43685e'

This commit is contained in:
Peter 2019-08-07 23:58:52 +03:00
commit 558bf41c4a
12 changed files with 634 additions and 567 deletions

View File

@ -135,14 +135,48 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
return self return self
} }
private func resolve(persons: [INPerson]?, with completion: @escaping ([INPersonResolutionResult]) -> Void) { enum ResolveResult {
guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else { case success(INPerson)
completion([INPersonResolutionResult.notRequired()]) case disambiguation([INPerson])
return case needsValue
case noResult
case skip
@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()
}
} }
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()
}
}
}
private func resolve(persons: [INPerson]?, with completion: @escaping ([ResolveResult]) -> Void) {
guard let initialPersons = persons, !initialPersons.isEmpty else { guard let initialPersons = persons, !initialPersons.isEmpty else {
completion([INPersonResolutionResult.needsValue()]) completion([.needsValue])
return return
} }
@ -164,12 +198,12 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
} }
if filteredPersons.isEmpty { if filteredPersons.isEmpty {
completion([INPersonResolutionResult.needsValue()]) completion([.noResult])
return return
} }
if filteredPersons.count > 1 { if filteredPersons.count > 1 {
completion([INPersonResolutionResult.disambiguation(with: filteredPersons)]) completion([.disambiguation(filteredPersons)])
return return
} }
@ -182,7 +216,7 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
} }
if allPersonsAlreadyMatched { if allPersonsAlreadyMatched {
completion([INPersonResolutionResult.success(with: filteredPersons[0])]) completion([.success(filteredPersons[0])])
return return
} }
@ -221,22 +255,29 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
self.resolvePersonsDisposable.set((signal self.resolvePersonsDisposable.set((signal
|> deliverOnMainQueue).start(next: { peers in |> deliverOnMainQueue).start(next: { peers in
if peers.isEmpty { if peers.isEmpty {
completion([INPersonResolutionResult.needsValue()]) completion([.needsValue])
} else { } else {
completion(peers.map { stableId, user in completion(peers.map { .success(personWithUser(stableId: $0, user: $1)) })
let person = personWithUser(stableId: stableId, user: user)
return INPersonResolutionResult.success(with: person)
})
} }
}, error: { error in }, error: { error in
completion([INPersonResolutionResult.unsupported()]) completion([.skip])
})) }))
} }
// MARK: - INSendMessageIntentHandling // MARK: - INSendMessageIntentHandling
func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) { func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
if #available(iOSApplicationExtension 11.0, *) { guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
completion([INPersonResolutionResult.notRequired()])
return
}
self.resolve(persons: intent.recipients, with: { result in
completion(result.map { $0.personResolutionResult })
})
}
@available(iOSApplicationExtension 11.0, *)
func resolveRecipients(for intent: INSendMessageIntent, with completion: @escaping ([INSendMessageRecipientResolutionResult]) -> Void) {
if let peerId = intent.conversationIdentifier.flatMap(Int64.init) { if let peerId = intent.conversationIdentifier.flatMap(Int64.init) {
let account = self.accountPromise.get() let account = self.accountPromise.get()
@ -261,18 +302,21 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
self.resolvePersonsDisposable.set((signal self.resolvePersonsDisposable.set((signal
|> deliverOnMainQueue).start(next: { person in |> deliverOnMainQueue).start(next: { person in
if let person = person { if let person = person {
completion([INPersonResolutionResult.success(with: person)]) completion([INSendMessageRecipientResolutionResult.success(with: person)])
} else { } else {
completion([INPersonResolutionResult.needsValue()]) completion([INSendMessageRecipientResolutionResult.needsValue()])
} }
}, error: { error in }, error: { error in
completion([INPersonResolutionResult.notRequired()]) completion([INSendMessageRecipientResolutionResult.unsupported(forReason: .noAccount)])
})) }))
} else { } else {
self.resolve(persons: intent.recipients, with: completion) guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
completion([INSendMessageRecipientResolutionResult.notRequired()])
return
} }
} else { self.resolve(persons: intent.recipients, with: { result in
self.resolve(persons: intent.recipients, with: completion) completion(result.map { $0.sendMessageRecipientResulutionResult })
})
} }
} }
@ -468,7 +512,13 @@ class IntentHandler: INExtension, INSendMessageIntentHandling, INSearchForMessag
// MARK: - INStartAudioCallIntentHandling // MARK: - INStartAudioCallIntentHandling
func resolveContacts(for intent: INStartAudioCallIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) { func resolveContacts(for intent: INStartAudioCallIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
self.resolve(persons: intent.contacts, with: completion) guard CNContactStore.authorizationStatus(for: .contacts) == .authorized else {
completion([INPersonResolutionResult.notRequired()])
return
}
self.resolve(persons: intent.contacts, with: { result in
completion(result.map { $0.personResolutionResult })
})
} }
func handle(intent: INStartAudioCallIntent, completion: @escaping (INStartAudioCallIntentResponse) -> Void) { func handle(intent: INStartAudioCallIntent, completion: @escaping (INStartAudioCallIntentResponse) -> Void) {

View File

@ -95,14 +95,17 @@ final class AlertControllerNode: ASDisplayNode {
self.bottomDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) self.bottomDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.leftDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) self.leftDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.rightDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3) self.rightDimView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { [weak self] _ in self.containerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, completion: { [weak self] finished in
if finished {
self?.centerDimView.backgroundColor = nil self?.centerDimView.backgroundColor = nil
self?.centerDimView.image = generateStretchableFilledCircleImage(radius: 16.0, color: nil, backgroundColor: UIColor(white: 0.0, alpha: 0.5)) self?.centerDimView.image = generateStretchableFilledCircleImage(radius: 16.0, color: nil, backgroundColor: UIColor(white: 0.0, alpha: 0.5))
}
}) })
self.containerNode.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, removeOnCompletion: true, additive: false, completion: nil) self.containerNode.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, removeOnCompletion: true, additive: false, completion: nil)
} }
func animateOut(completion: @escaping () -> Void) { func animateOut(completion: @escaping () -> Void) {
self.containerNode.layer.removeAllAnimations()
self.centerDimView.backgroundColor = UIColor(white: 0.0, alpha: 0.5) self.centerDimView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
self.centerDimView.image = nil self.centerDimView.image = nil

View File

@ -1121,13 +1121,13 @@ final class SharedApplicationContext {
Logger.shared.log("App \(self.episodeId)", "isActive = \(value)") Logger.shared.log("App \(self.episodeId)", "isActive = \(value)")
}) })
/*if let url = launchOptions?[.url] { if let url = launchOptions?[.url] {
if let url = url as? URL, url.scheme == "tg" { if let url = url as? URL, url.scheme == "tg" {
self.openUrlWhenReady(url: url.absoluteString) self.openUrlWhenReady(url: url.absoluteString)
} else if let url = url as? String, url.lowercased().hasPrefix("tg://") { } else if let url = url as? String, url.lowercased().hasPrefix("tg://") {
self.openUrlWhenReady(url: url) self.openUrlWhenReady(url: url)
} }
}*/ }
if application.applicationState == .active { if application.applicationState == .active {
self.isInForegroundValue = true self.isInForegroundValue = true
@ -1845,7 +1845,7 @@ final class SharedApplicationContext {
notificationCenter.getNotificationSettings(completionHandler: { settings in notificationCenter.getNotificationSettings(completionHandler: { settings in
switch (settings.authorizationStatus, authorize) { switch (settings.authorizationStatus, authorize) {
case (.authorized, _), (.notDetermined, true): case (.authorized, _), (.notDetermined, true):
notificationCenter.requestAuthorization(options: [.badge, .sound, .alert, .carPlay], completionHandler: { result, _ in notificationCenter.requestAuthorization(options: [.badge, .sound, .alert], completionHandler: { result, _ in
completion(result) completion(result)
if result { if result {
Queue.mainQueue().async { Queue.mainQueue().async {
@ -1867,7 +1867,7 @@ final class SharedApplicationContext {
} }
var carPlayOptions = options var carPlayOptions = options
carPlayOptions.insert(.allowInCarPlay) //carPlayOptions.insert(.allowInCarPlay)
unknownMessageCategory = UNNotificationCategory(identifier: "unknown", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options) unknownMessageCategory = UNNotificationCategory(identifier: "unknown", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions) replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: carPlayOptions)
@ -1878,7 +1878,7 @@ final class SharedApplicationContext {
muteMessageCategory = UNNotificationCategory(identifier: "withMute", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options) muteMessageCategory = UNNotificationCategory(identifier: "withMute", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
muteMediaMessageCategory = UNNotificationCategory(identifier: "withMuteMedia", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options) muteMediaMessageCategory = UNNotificationCategory(identifier: "withMuteMedia", actions: [], intentIdentifiers: [], hiddenPreviewsBodyPlaceholder: hiddenContentString, options: options)
} else { } else {
let carPlayOptions: UNNotificationCategoryOptions = [.allowInCarPlay] let carPlayOptions: UNNotificationCategoryOptions = [] //[.allowInCarPlay]
unknownMessageCategory = UNNotificationCategory(identifier: "unknown", actions: [], intentIdentifiers: [], options: []) unknownMessageCategory = UNNotificationCategory(identifier: "unknown", actions: [], intentIdentifiers: [], options: [])
replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], options: carPlayOptions) replyMessageCategory = UNNotificationCategory(identifier: "withReply", actions: [reply], intentIdentifiers: [INSearchForMessagesIntentIdentifier], options: carPlayOptions)

View File

@ -15,7 +15,7 @@ private func timerValueString(days: Int32, hours: Int32, minutes: Int32, color:
var hoursString = "" var hoursString = ""
if hours > 0 || days > 0 { if hours > 0 || days > 0 {
daysString = strings.MessageTimer_Hours(hours) + " " hoursString = strings.MessageTimer_Hours(hours) + " "
} }
let minutesString = strings.MessageTimer_Minutes(minutes) let minutesString = strings.MessageTimer_Minutes(minutes)

View File

@ -846,6 +846,14 @@ public class ChatListController: TelegramBaseController, UIViewControllerPreview
} }
} }
self.chatListDisplayNode.isEmptyUpdated = { [weak self] isEmpty in
if let strongSelf = self, let searchContentNode = strongSelf.searchContentNode, let validLayout = strongSelf.validLayout {
if isEmpty {
searchContentNode.updateListVisibleContentOffset(.known(0.0))
}
}
}
self.chatListDisplayNode.toolbarActionSelected = { [weak self] action in self.chatListDisplayNode.toolbarActionSelected = { [weak self] action in
self?.toolbarActionSelected(action: action) self?.toolbarActionSelected(action: action)
} }

View File

@ -63,6 +63,7 @@ final class ChatListControllerNode: ASDisplayNode {
var requestOpenMessageFromSearch: ((Peer, MessageId) -> Void)? var requestOpenMessageFromSearch: ((Peer, MessageId) -> Void)?
var requestAddContact: ((String) -> Void)? var requestAddContact: ((String) -> Void)?
var dismissSelf: (() -> Void)? var dismissSelf: (() -> Void)?
var isEmptyUpdated: ((Bool) -> Void)?
let debugListView = ListView() let debugListView = ListView()
@ -99,6 +100,7 @@ final class ChatListControllerNode: ASDisplayNode {
if let (layout, navigationHeight, visualNavigationHeight) = strongSelf.containerLayout { if let (layout, navigationHeight, visualNavigationHeight) = strongSelf.containerLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, visualNavigationHeight: visualNavigationHeight, transition: .immediate) strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, visualNavigationHeight: visualNavigationHeight, transition: .immediate)
} }
strongSelf.isEmptyUpdated?(true)
} }
case .notEmpty(false): case .notEmpty(false):
if case .group = strongSelf.groupId { if case .group = strongSelf.groupId {

View File

@ -19,6 +19,8 @@ extension UnicodeScalar {
return true return true
case 0x1f004: case 0x1f004:
return true return true
case 0x2764:
return true
case 0x270b, 0x2728: case 0x270b, 0x2728:
return true return true
default: default:

View File

@ -294,7 +294,9 @@ public class ShareRootControllerImpl {
} }
cancelImpl = { [weak shareController] in cancelImpl = { [weak shareController] in
shareController?.dismiss() shareController?.dismiss(completion: { [weak self] in
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
})
} }
if let strongSelf = self { if let strongSelf = self {