mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-02 00:17:02 +00:00
Donate send message intents when posting from share controller
Clear donated send message intents on logout
This commit is contained in:
parent
f3120ee918
commit
8ca47c3aef
23
submodules/AppIntents/BUCK
Normal file
23
submodules/AppIntents/BUCK
Normal file
@ -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",
|
||||||
|
],
|
||||||
|
)
|
22
submodules/AppIntents/Info.plist
Normal file
22
submodules/AppIntents/Info.plist
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
67
submodules/AppIntents/Sources/AppIntents.swift
Normal file
67
submodules/AppIntents/Sources/AppIntents.swift
Normal file
@ -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())")
|
||||||
|
}
|
||||||
|
}
|
@ -23,6 +23,7 @@ static_library(
|
|||||||
"//submodules/ActivityIndicator:ActivityIndicator",
|
"//submodules/ActivityIndicator:ActivityIndicator",
|
||||||
"//submodules/AppBundle:AppBundle",
|
"//submodules/AppBundle:AppBundle",
|
||||||
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
|
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
|
||||||
|
"//submodules/AppIntents:AppIntents",
|
||||||
],
|
],
|
||||||
frameworks = [
|
frameworks = [
|
||||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||||
|
@ -8,6 +8,7 @@ import TelegramCore
|
|||||||
import SyncCore
|
import SyncCore
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import AppIntents
|
||||||
|
|
||||||
enum ShareState {
|
enum ShareState {
|
||||||
case preparing
|
case preparing
|
||||||
@ -26,6 +27,7 @@ func openExternalShare(state: () -> Signal<ShareExternalState, NoError>) {
|
|||||||
|
|
||||||
final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate {
|
final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate {
|
||||||
private let sharedContext: SharedAccountContext
|
private let sharedContext: SharedAccountContext
|
||||||
|
private var account: Account?
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private let externalShare: Bool
|
private let externalShare: Bool
|
||||||
private let immediateExternalShare: Bool
|
private let immediateExternalShare: Bool
|
||||||
@ -537,6 +539,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
peerIds = self.controllerInteraction!.selectedPeers.map { $0.peerId }
|
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) {
|
if let signal = self.share?(self.inputFieldNode.text, peerIds) {
|
||||||
self.transitionToContentNode(ShareLoadingContainerNode(theme: self.presentationData.theme, forceNativeAppearance: true), fastOut: true)
|
self.transitionToContentNode(ShareLoadingContainerNode(theme: self.presentationData.theme, forceNativeAppearance: true), fastOut: true)
|
||||||
let timestamp = CACurrentMediaTime()
|
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?) {
|
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 {
|
if let peersContentNode = self.peersContentNode, peersContentNode.accountPeer.id == accountPeer.id {
|
||||||
peersContentNode.peersValue.set(.single(peers))
|
peersContentNode.peersValue.set(.single(peers))
|
||||||
return
|
return
|
||||||
|
@ -197,6 +197,7 @@ framework(
|
|||||||
"//submodules/AppLock:AppLock",
|
"//submodules/AppLock:AppLock",
|
||||||
"//submodules/NotificationsPresentationData:NotificationsPresentationData",
|
"//submodules/NotificationsPresentationData:NotificationsPresentationData",
|
||||||
"//submodules/UrlWhitelist:UrlWhitelist",
|
"//submodules/UrlWhitelist:UrlWhitelist",
|
||||||
|
"//submodules/AppIntents:AppIntents",
|
||||||
],
|
],
|
||||||
frameworks = [
|
frameworks = [
|
||||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||||
|
@ -33,6 +33,7 @@ import WalletCore
|
|||||||
import OpenSSLEncryptionProvider
|
import OpenSSLEncryptionProvider
|
||||||
import AppLock
|
import AppLock
|
||||||
import PresentationDataUtils
|
import PresentationDataUtils
|
||||||
|
import AppIntents
|
||||||
|
|
||||||
#if canImport(BackgroundTasks)
|
#if canImport(BackgroundTasks)
|
||||||
import BackgroundTasks
|
import BackgroundTasks
|
||||||
@ -179,6 +180,8 @@ final class SharedApplicationContext {
|
|||||||
private let authContext = Promise<UnauthorizedApplicationContext?>()
|
private let authContext = Promise<UnauthorizedApplicationContext?>()
|
||||||
private let authContextDisposable = MetaDisposable()
|
private let authContextDisposable = MetaDisposable()
|
||||||
|
|
||||||
|
private let logoutDisposable = MetaDisposable()
|
||||||
|
|
||||||
private let openChatWhenReadyDisposable = MetaDisposable()
|
private let openChatWhenReadyDisposable = MetaDisposable()
|
||||||
private let openUrlWhenReadyDisposable = MetaDisposable()
|
private let openUrlWhenReadyDisposable = MetaDisposable()
|
||||||
|
|
||||||
@ -1155,7 +1158,8 @@ final class SharedApplicationContext {
|
|||||||
}
|
}
|
||||||
|> take(1)
|
|> take(1)
|
||||||
|> timeout(4.0, queue: .mainQueue(), alternate: .complete())
|
|> 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()
|
authContextValue.rootController.dismiss()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -1174,12 +1178,32 @@ final class SharedApplicationContext {
|
|||||||
|> take(1)
|
|> take(1)
|
||||||
|> deliverOnMainQueue).start(next: { _ in
|
|> deliverOnMainQueue).start(next: { _ in
|
||||||
statusController.dismiss()
|
statusController.dismiss()
|
||||||
self.mainWindow.present(context.rootController, on: .root) }))
|
self.mainWindow.present(context.rootController, on: .root)
|
||||||
|
}))
|
||||||
} else {
|
} else {
|
||||||
authContextReadyDisposable.set(nil)
|
authContextReadyDisposable.set(nil)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
self.logoutDisposable.set((self.sharedContextPromise.get()
|
||||||
|
|> take(1)
|
||||||
|
|> mapToSignal { sharedContext -> Signal<Set<PeerId>, NoError> in
|
||||||
|
return sharedContext.sharedContext.activeAccounts
|
||||||
|
|> map { _, accounts, _ -> Set<PeerId> in
|
||||||
|
return Set(accounts.map { $0.1.peerId })
|
||||||
|
}
|
||||||
|
|> reduceLeft(value: Set<PeerId>()) { 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
|
self.watchCommunicationManagerPromise.set(watchCommunicationManager(context: self.context.get() |> flatMap { WatchCommunicationManagerContext(context: $0.context) }, allowBackgroundTimeExtension: { timeout in
|
||||||
let _ = (self.sharedContextPromise.get()
|
let _ = (self.sharedContextPromise.get()
|
||||||
|> take(1)).start(next: { sharedContext in
|
|> take(1)).start(next: { sharedContext in
|
||||||
|
@ -55,6 +55,7 @@ import LocalizedPeerData
|
|||||||
import PhoneNumberFormat
|
import PhoneNumberFormat
|
||||||
import SettingsUI
|
import SettingsUI
|
||||||
import UrlWhitelist
|
import UrlWhitelist
|
||||||
|
import AppIntents
|
||||||
|
|
||||||
public enum ChatControllerPeekActions {
|
public enum ChatControllerPeekActions {
|
||||||
case standard
|
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 {
|
} else {
|
||||||
let mode: ChatScheduleTimeControllerMode
|
let mode: ChatScheduleTimeControllerMode
|
||||||
if peerId == self.context.account.peerId {
|
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() {
|
private func updateReminderActivity() {
|
||||||
if self.isReminderActivityEnabled && false {
|
if self.isReminderActivityEnabled && false {
|
||||||
if #available(iOS 9.0, *) {
|
if #available(iOS 9.0, *) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user