diff --git a/submodules/AppIntents/BUCK b/submodules/AppIntents/BUCK
new file mode 100644
index 0000000000..2bc4100875
--- /dev/null
+++ b/submodules/AppIntents/BUCK
@@ -0,0 +1,23 @@
+load("//Config:buck_rule_macros.bzl", "static_library")
+
+static_library(
+ name = "AppIntents",
+ srcs = glob([
+ "Sources/**/*.swift",
+ ]),
+ deps = [
+ "//submodules/TelegramCore:TelegramCore#shared",
+ "//submodules/SyncCore:SyncCore#shared",
+ "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
+ "//submodules/Display:Display#shared",
+ "//submodules/AccountContext:AccountContext",
+ "//submodules/TelegramPresentationData:TelegramPresentationData",
+ "//submodules/AvatarNode:AvatarNode",
+ ],
+ frameworks = [
+ "$SDKROOT/System/Library/Frameworks/Foundation.framework",
+ ],
+ weak_frameworks = [
+ "Intents",
+ ],
+)
diff --git a/submodules/AppIntents/Info.plist b/submodules/AppIntents/Info.plist
new file mode 100644
index 0000000000..e1fe4cfb7b
--- /dev/null
+++ b/submodules/AppIntents/Info.plist
@@ -0,0 +1,22 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ FMWK
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ $(CURRENT_PROJECT_VERSION)
+
+
diff --git a/submodules/AppIntents/Sources/AppIntents.swift b/submodules/AppIntents/Sources/AppIntents.swift
new file mode 100644
index 0000000000..676d2373cc
--- /dev/null
+++ b/submodules/AppIntents/Sources/AppIntents.swift
@@ -0,0 +1,67 @@
+import Foundation
+import UIKit
+import Intents
+import Display
+import Postbox
+import TelegramCore
+import SyncCore
+import SwiftSignalKit
+import TelegramPresentationData
+import AvatarNode
+import AccountContext
+
+public func donateSendMessageIntent(account: Account, sharedContext: SharedAccountContext, peerIds: [PeerId]) {
+ if #available(iOSApplicationExtension 13.2, iOS 13.2, *) {
+ let _ = (account.postbox.transaction { transaction -> [Peer] in
+ var peers: [Peer] = []
+ for peerId in peerIds {
+ if peerId.namespace == Namespaces.Peer.CloudUser && peerId != account.peerId, let peer = transaction.getPeer(peerId) {
+ peers.append(peer)
+ }
+ }
+ return peers
+ }
+ |> mapToSignal { peers -> Signal<[(Peer, UIImage?)], NoError> in
+ var signals: [Signal<(Peer, UIImage?), NoError>] = []
+ for peer in peers {
+ let peerAndAvatar = (peerAvatarImage(account: account, peer: peer, authorOfMessage: nil, representation: peer.smallProfileImage, round: false) ?? .single(nil))
+ |> map { avatarImage in
+ return (peer, avatarImage)
+ }
+ signals.append(peerAndAvatar)
+ }
+ return combineLatest(signals)
+ }
+ |> deliverOnMainQueue).start(next: { peers in
+ for (peer, avatarImage) in peers {
+ guard let peer = peer as? TelegramUser, peer.botInfo == nil && !peer.flags.contains(.isSupport) else {
+ continue
+ }
+ let presentationData = sharedContext.currentPresentationData.with { $0 }
+
+ let recipientHandle = INPersonHandle(value: "tg\(peer.id.id)", type: .unknown)
+ var nameComponents = PersonNameComponents()
+ nameComponents.givenName = peer.firstName
+ nameComponents.familyName = peer.lastName
+
+ let displayTitle = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
+ let recipient = INPerson(personHandle: recipientHandle, nameComponents: nameComponents, displayName: displayTitle, image: nil, contactIdentifier: nil, customIdentifier: "tg\(peer.id.id)")
+
+ let intent = INSendMessageIntent(recipients: [recipient], content: nil, speakableGroupName: INSpeakableString(spokenPhrase: displayTitle), conversationIdentifier: "tg\(peer.id.id)", serviceName: nil, sender: nil)
+ if let avatarImage = avatarImage, let avatarImageData = avatarImage.jpegData(compressionQuality: 0.8) {
+ intent.setImage(INImage(imageData: avatarImageData), forParameterNamed: \.groupName)
+ }
+ let interaction = INInteraction(intent: intent, response: nil)
+ interaction.direction = .outgoing
+ interaction.groupIdentifier = "sendMessage_\(account.peerId.toInt64())"
+ interaction.donate()
+ }
+ })
+ }
+}
+
+public func deleteAllSendMessageIntents(accountPeerId: PeerId) {
+ if #available(iOS 10.0, *) {
+ INInteraction.delete(with: "sendMessage_\(accountPeerId.toInt64())")
+ }
+}
diff --git a/submodules/ShareController/BUCK b/submodules/ShareController/BUCK
index e67eab7f9c..9a5616a4e9 100644
--- a/submodules/ShareController/BUCK
+++ b/submodules/ShareController/BUCK
@@ -23,6 +23,7 @@ static_library(
"//submodules/ActivityIndicator:ActivityIndicator",
"//submodules/AppBundle:AppBundle",
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
+ "//submodules/AppIntents:AppIntents",
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
diff --git a/submodules/ShareController/Sources/ShareControllerNode.swift b/submodules/ShareController/Sources/ShareControllerNode.swift
index ce4adcd07e..1f5bfd5785 100644
--- a/submodules/ShareController/Sources/ShareControllerNode.swift
+++ b/submodules/ShareController/Sources/ShareControllerNode.swift
@@ -8,6 +8,7 @@ import TelegramCore
import SyncCore
import TelegramPresentationData
import AccountContext
+import AppIntents
enum ShareState {
case preparing
@@ -26,6 +27,7 @@ func openExternalShare(state: () -> Signal) {
final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate {
private let sharedContext: SharedAccountContext
+ private var account: Account?
private var presentationData: PresentationData
private let externalShare: Bool
private let immediateExternalShare: Bool
@@ -537,6 +539,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
peerIds = self.controllerInteraction!.selectedPeers.map { $0.peerId }
}
+ if let account = self.account {
+ donateSendMessageIntent(account: account, sharedContext: self.sharedContext, peerIds: peerIds)
+ }
+
if let signal = self.share?(self.inputFieldNode.text, peerIds) {
self.transitionToContentNode(ShareLoadingContainerNode(theme: self.presentationData.theme, forceNativeAppearance: true), fastOut: true)
let timestamp = CACurrentMediaTime()
@@ -629,6 +635,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
}
func updatePeers(account: Account, switchableAccounts: [AccountWithInfo], peers: [(RenderedPeer, PeerPresence?)], accountPeer: Peer, defaultAction: ShareControllerAction?) {
+ self.account = account
+
if let peersContentNode = self.peersContentNode, peersContentNode.accountPeer.id == accountPeer.id {
peersContentNode.peersValue.set(.single(peers))
return
diff --git a/submodules/TelegramUI/BUCK b/submodules/TelegramUI/BUCK
index 4b6ef3822d..35d07b5256 100644
--- a/submodules/TelegramUI/BUCK
+++ b/submodules/TelegramUI/BUCK
@@ -197,6 +197,7 @@ framework(
"//submodules/AppLock:AppLock",
"//submodules/NotificationsPresentationData:NotificationsPresentationData",
"//submodules/UrlWhitelist:UrlWhitelist",
+ "//submodules/AppIntents:AppIntents",
],
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
diff --git a/submodules/TelegramUI/TelegramUI/AppDelegate.swift b/submodules/TelegramUI/TelegramUI/AppDelegate.swift
index 8a085da8b9..49844c444f 100644
--- a/submodules/TelegramUI/TelegramUI/AppDelegate.swift
+++ b/submodules/TelegramUI/TelegramUI/AppDelegate.swift
@@ -33,6 +33,7 @@ import WalletCore
import OpenSSLEncryptionProvider
import AppLock
import PresentationDataUtils
+import AppIntents
#if canImport(BackgroundTasks)
import BackgroundTasks
@@ -179,6 +180,8 @@ final class SharedApplicationContext {
private let authContext = Promise()
private let authContextDisposable = MetaDisposable()
+ private let logoutDisposable = MetaDisposable()
+
private let openChatWhenReadyDisposable = MetaDisposable()
private let openUrlWhenReadyDisposable = MetaDisposable()
@@ -1155,7 +1158,8 @@ final class SharedApplicationContext {
}
|> take(1)
|> timeout(4.0, queue: .mainQueue(), alternate: .complete())
- |> deliverOnMainQueue).start(completed: { authContextValue.rootController.view.endEditing(true)
+ |> deliverOnMainQueue).start(completed: {
+ authContextValue.rootController.view.endEditing(true)
authContextValue.rootController.dismiss()
})
} else {
@@ -1174,12 +1178,32 @@ final class SharedApplicationContext {
|> take(1)
|> deliverOnMainQueue).start(next: { _ in
statusController.dismiss()
- self.mainWindow.present(context.rootController, on: .root) }))
+ self.mainWindow.present(context.rootController, on: .root)
+ }))
} else {
authContextReadyDisposable.set(nil)
}
}))
+ self.logoutDisposable.set((self.sharedContextPromise.get()
+ |> take(1)
+ |> mapToSignal { sharedContext -> Signal, NoError> in
+ return sharedContext.sharedContext.activeAccounts
+ |> map { _, accounts, _ -> Set in
+ return Set(accounts.map { $0.1.peerId })
+ }
+ |> reduceLeft(value: Set()) { current, updated, emit in
+ if !current.isEmpty {
+ emit(current.subtracting(current.intersection(updated)))
+ }
+ return updated
+ }
+ }).start(next: { loggedOutAccountPeerIds in
+ for peerId in loggedOutAccountPeerIds {
+ deleteAllSendMessageIntents(accountPeerId: peerId)
+ }
+ }))
+
self.watchCommunicationManagerPromise.set(watchCommunicationManager(context: self.context.get() |> flatMap { WatchCommunicationManagerContext(context: $0.context) }, allowBackgroundTimeExtension: { timeout in
let _ = (self.sharedContextPromise.get()
|> take(1)).start(next: { sharedContext in
diff --git a/submodules/TelegramUI/TelegramUI/ChatController.swift b/submodules/TelegramUI/TelegramUI/ChatController.swift
index c789824280..13c834f324 100644
--- a/submodules/TelegramUI/TelegramUI/ChatController.swift
+++ b/submodules/TelegramUI/TelegramUI/ChatController.swift
@@ -55,6 +55,7 @@ import LocalizedPeerData
import PhoneNumberFormat
import SettingsUI
import UrlWhitelist
+import AppIntents
public enum ChatControllerPeekActions {
case standard
@@ -2798,7 +2799,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
})
- strongSelf.donateSendMessageIntent()
+ donateSendMessageIntent(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, peerIds: [peerId])
}
}
@@ -5994,7 +5995,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
})
- self.donateSendMessageIntent()
+ donateSendMessageIntent(account: self.context.account, sharedContext: self.context.sharedContext, peerIds: [peerId])
} else {
let mode: ChatScheduleTimeControllerMode
if peerId == self.context.account.peerId {
@@ -8067,44 +8068,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
}
- private func donateSendMessageIntent() {
- guard case let .peer(peerId) = self.chatLocation, peerId.namespace == Namespaces.Peer.CloudUser && peerId != self.context.account.peerId else {
- return
- }
- if #available(iOSApplicationExtension 13.2, iOS 13.2, *) {
- let _ = (self.context.account.postbox.loadedPeerWithId(peerId)
- |> mapToSignal { peer -> Signal<(Peer, UIImage?), NoError> in
- let avatarImage = peerAvatarImage(account: self.context.account, peer: peer, authorOfMessage: nil, representation: peer.smallProfileImage, round: false) ?? .single(nil)
- return avatarImage
- |> map { avatarImage in
- return (peer, avatarImage)
- }
- }
- |> deliverOnMainQueue).start(next: { [weak self] peer, avatarImage in
- if let strongSelf = self, let peer = peer as? TelegramUser, peer.botInfo == nil && !peer.flags.contains(.isSupport) {
- let recipientHandle = INPersonHandle(value: "tg\(peerId.id)", type: .unknown)
- var nameComponents = PersonNameComponents()
- nameComponents.givenName = peer.firstName
- nameComponents.familyName = peer.lastName
- let displayTitle = peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder)
- let recipient = INPerson(personHandle: recipientHandle, nameComponents: nameComponents, displayName: displayTitle, image: nil, contactIdentifier: nil, customIdentifier: "tg\(peerId.id)")
- let intent = INSendMessageIntent(recipients: [recipient], content: nil, speakableGroupName: INSpeakableString(spokenPhrase: displayTitle), conversationIdentifier: "tg\(peerId.id)", serviceName: nil, sender: nil)
- if #available(iOS 12.0, *), let avatarImage = avatarImage, let avatarImageData = avatarImage.jpegData(compressionQuality: 0.8) {
- intent.setImage(INImage(imageData: avatarImageData), forParameterNamed: \.groupName)
- }
- let interaction = INInteraction(intent: intent, response: nil)
- interaction.direction = .outgoing
- interaction.groupIdentifier = "sendMessage_\(strongSelf.context.account.peerId.toInt64())"
- interaction.donate { error in
- if let error = error {
- print(error.localizedDescription)
- }
- }
- }
- })
- }
- }
-
private func updateReminderActivity() {
if self.isReminderActivityEnabled && false {
if #available(iOS 9.0, *) {