Improve Share Suggestion execution flow

This commit is contained in:
Ilya Laktyushin 2019-11-28 18:22:40 +04:00
parent 45224e6e96
commit 5e620dc318
6 changed files with 94 additions and 59 deletions

View File

@ -426,7 +426,7 @@ public final class ShareController: ViewController {
return return
} }
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare) }, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare, immediatePeerId: self.immediatePeerId)
self.controllerNode.dismiss = { [weak self] shared in self.controllerNode.dismiss = { [weak self] shared in
self?.presentingViewController?.dismiss(animated: false, completion: nil) self?.presentingViewController?.dismiss(animated: false, completion: nil)
self?.dismissed?(shared) self?.dismissed?(shared)
@ -704,15 +704,12 @@ public final class ShareController: ViewController {
} }
self.displayNodeDidLoad() self.displayNodeDidLoad()
if let _ = self.immediatePeerId { self.peersDisposable.set((self.peers.get()
} else { |> deliverOnMainQueue).start(next: { [weak self] next in
self.peersDisposable.set((self.peers.get() if let strongSelf = self {
|> deliverOnMainQueue).start(next: { [weak self] next in strongSelf.controllerNode.updatePeers(account: strongSelf.currentAccount, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction)
if let strongSelf = self { }
strongSelf.controllerNode.updatePeers(account: strongSelf.currentAccount, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction) }))
}
}))
}
self._ready.set(self.controllerNode.ready.get()) self._ready.set(self.controllerNode.ready.get())
} }
@ -827,31 +824,23 @@ public final class ShareController: ViewController {
return (resultPeers, accountPeer) return (resultPeers, accountPeer)
} }
}) })
if let immediatePeerId = self.immediatePeerId { self.peersDisposable.set((self.peers.get()
self.sendImmediately(peerId: immediatePeerId) |> deliverOnMainQueue).start(next: { [weak self] next in
} else { if let strongSelf = self {
self.peersDisposable.set((self.peers.get() strongSelf.controllerNode.updatePeers(account: strongSelf.currentAccount, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction)
|> deliverOnMainQueue).start(next: { [weak self] next in
if let strongSelf = self { if animateIn {
strongSelf.controllerNode.updatePeers(account: strongSelf.currentAccount, switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction) strongSelf.readyDisposable.set((strongSelf.controllerNode.ready.get()
|> filter({ $0 })
if animateIn { |> take(1)
strongSelf.readyDisposable.set((strongSelf.controllerNode.ready.get() |> deliverOnMainQueue).start(next: { [weak self] _ in
|> filter({ $0 }) guard let strongSelf = self else {
|> take(1) return
|> deliverOnMainQueue).start(next: { [weak self] _ in }
guard let strongSelf = self else { strongSelf.controllerNode.animateIn()
return }))
}
strongSelf.controllerNode.animateIn()
}))
}
} }
})) }
} }))
}
private func sendImmediately(peerId: PeerId) {
self.controllerNode.send(peerId: peerId)
} }
} }

View File

@ -31,6 +31,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
private var presentationData: PresentationData private var presentationData: PresentationData
private let externalShare: Bool private let externalShare: Bool
private let immediateExternalShare: Bool private let immediateExternalShare: Bool
private var immediatePeerId: PeerId?
private let defaultAction: ShareControllerAction? private let defaultAction: ShareControllerAction?
private let requestLayout: (ContainedViewLayoutTransition) -> Void private let requestLayout: (ContainedViewLayoutTransition) -> Void
@ -75,11 +76,12 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
private var hapticFeedback: HapticFeedback? private var hapticFeedback: HapticFeedback?
init(sharedContext: SharedAccountContext, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool) { init(sharedContext: SharedAccountContext, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?) {
self.sharedContext = sharedContext self.sharedContext = sharedContext
self.presentationData = sharedContext.currentPresentationData.with { $0 } self.presentationData = sharedContext.currentPresentationData.with { $0 }
self.externalShare = externalShare self.externalShare = externalShare
self.immediateExternalShare = immediateExternalShare self.immediateExternalShare = immediateExternalShare
self.immediatePeerId = immediatePeerId
self.presentError = presentError self.presentError = presentError
self.defaultAction = defaultAction self.defaultAction = defaultAction
@ -151,7 +153,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
} }
super.init() super.init()
self.controllerInteraction = ShareControllerInteraction(togglePeer: { [weak self] peer, search in self.controllerInteraction = ShareControllerInteraction(togglePeer: { [weak self] peer, search in
if let strongSelf = self { if let strongSelf = self {
var added = false var added = false
@ -642,6 +644,17 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
return return
} }
if let peerId = self.immediatePeerId {
self.immediatePeerId = nil
let _ = (account.postbox.transaction { transaction -> RenderedPeer? in
return transaction.getPeer(peerId).flatMap(RenderedPeer.init(peer:))
} |> deliverOnMainQueue).start(next: { [weak self] peer in
if let strongSelf = self, let peer = peer {
strongSelf.controllerInteraction?.togglePeer(peer, true)
}
})
}
let animated = self.peersContentNode == nil let animated = self.peersContentNode == nil
let peersContentNode = SharePeersContainerNode(sharedContext: self.sharedContext, account: account, switchableAccounts: switchableAccounts, theme: self.presentationData.theme, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, peers: peers, accountPeer: accountPeer, controllerInteraction: self.controllerInteraction!, externalShare: self.externalShare, switchToAnotherAccount: { [weak self] in let peersContentNode = SharePeersContainerNode(sharedContext: self.sharedContext, account: account, switchableAccounts: switchableAccounts, theme: self.presentationData.theme, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder, peers: peers, accountPeer: accountPeer, controllerInteraction: self.controllerInteraction!, externalShare: self.externalShare, switchToAnotherAccount: { [weak self] in
self?.switchToAnotherAccount?() self?.switchToAnotherAccount?()

View File

@ -181,9 +181,13 @@ public func donateSendMessageIntent(account: Account, sharedContext: SharedAccou
} }
let interaction = INInteraction(intent: intent, response: nil) let interaction = INInteraction(intent: intent, response: nil)
interaction.direction = .outgoing interaction.direction = .outgoing
interaction.identifier = "sendMessage_\(account.peerId.toInt64())_\(peer.id.toInt64)" interaction.identifier = "sendMessage_\(account.peerId.toInt64())_\(peer.id.toInt64())"
interaction.groupIdentifier = "sendMessage_\(subject.toString())_\(account.peerId.toInt64())" interaction.groupIdentifier = "sendMessage_\(subject.toString())_\(account.peerId.toInt64())"
interaction.donate() interaction.donate { error in
if let error = error {
print(error)
}
}
} }
}) })
} }
@ -191,7 +195,7 @@ public func donateSendMessageIntent(account: Account, sharedContext: SharedAccou
public func deleteSendMessageIntents(account: Account, peerId: PeerId) { public func deleteSendMessageIntents(account: Account, peerId: PeerId) {
if #available(iOS 10.0, *) { if #available(iOS 10.0, *) {
INInteraction.delete(with: ["sendMessage_\(account.peerId.toInt64())_\(peerId.toInt64)"]) INInteraction.delete(with: ["sendMessage_\(account.peerId.toInt64())_\(peerId.toInt64())"])
} }
} }

View File

@ -1199,7 +1199,7 @@ final class SharedApplicationContext {
self.logoutDisposable.set((self.sharedContextPromise.get() self.logoutDisposable.set((self.sharedContextPromise.get()
|> take(1) |> take(1)
|> mapToSignal { sharedContext -> Signal<Set<PeerId>, NoError> in |> mapToSignal { sharedContext -> Signal<(AccountManager, Set<PeerId>), NoError> in
return sharedContext.sharedContext.activeAccounts return sharedContext.sharedContext.activeAccounts
|> map { _, accounts, _ -> Set<PeerId> in |> map { _, accounts, _ -> Set<PeerId> in
return Set(accounts.map { $0.1.peerId }) return Set(accounts.map { $0.1.peerId })
@ -1210,10 +1210,27 @@ final class SharedApplicationContext {
} }
return updated return updated
} }
}).start(next: { loggedOutAccountPeerIds in |> map { loggedOutAccountPeerIds -> (AccountManager, Set<PeerId>) in
return (sharedContext.sharedContext.accountManager, loggedOutAccountPeerIds)
}
}).start(next: { [weak self] accountManager, loggedOutAccountPeerIds in
guard let strongSelf = self else {
return
}
for peerId in loggedOutAccountPeerIds { for peerId in loggedOutAccountPeerIds {
deleteAllSendMessageIntents(accountPeerId: peerId) deleteAllSendMessageIntents(accountPeerId: peerId)
} }
let _ = (updateIntentsSettingsInteractively(accountManager: accountManager) { current in
var updated = current
for peerId in loggedOutAccountPeerIds {
if peerId == updated.account {
updated = updated.withUpdatedAccount(nil)
break
}
}
return updated
}).start()
})) }))
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

View File

@ -198,6 +198,16 @@ public class ShareRootControllerImpl {
globalInternalContext = internalContext globalInternalContext = internalContext
} }
var immediatePeerId: PeerId?
if #available(iOS 13.2, *), let sendMessageIntent = self.getExtensionContext()?.intent as? INSendMessageIntent {
if let contact = sendMessageIntent.recipients?.first, let handle = contact.customIdentifier, handle.hasPrefix("tg") {
let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2))
if let userId = Int32(string) {
immediatePeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
}
}
}
let account: Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> = internalContext.sharedContext.accountManager.transaction { transaction -> (SharedAccountContextImpl, LoggingSettings) in let account: Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> = internalContext.sharedContext.accountManager.transaction { transaction -> (SharedAccountContextImpl, LoggingSettings) in
return (internalContext.sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings) return (internalContext.sharedContext, transaction.getSharedData(SharedDataKeys.loggingSettings) as? LoggingSettings ?? LoggingSettings.defaultSettings)
} }
@ -208,24 +218,36 @@ public class ShareRootControllerImpl {
Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData
return combineLatest(sharedContext.activeAccountsWithInfo, accountManager.transaction { transaction -> Set<AccountRecordId> in return combineLatest(sharedContext.activeAccountsWithInfo, accountManager.transaction { transaction -> (Set<AccountRecordId>, PeerId?) in
return Set(transaction.getRecords().map { record in let accountRecords = Set(transaction.getRecords().map { record in
return record.id return record.id
}) })
let intentsSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.intentsSettings) as? IntentsSettings ?? IntentsSettings.defaultSettings
return (accountRecords, intentsSettings.account)
}) })
|> castError(ShareAuthorizationError.self) |> castError(ShareAuthorizationError.self)
|> take(1) |> take(1)
|> mapToSignal { primaryAndAccounts, validAccountIds -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in |> mapToSignal { primaryAndAccounts, validAccountIdsAndIntentsAccountId -> Signal<(SharedAccountContextImpl, Account, [AccountWithInfo]), ShareAuthorizationError> in
var (maybePrimary, accounts) = primaryAndAccounts var (maybePrimary, accounts) = primaryAndAccounts
let (validAccountIds, intentsAccountId) = validAccountIdsAndIntentsAccountId
for i in (0 ..< accounts.count).reversed() { for i in (0 ..< accounts.count).reversed() {
if !validAccountIds.contains(accounts[i].account.id) { if !validAccountIds.contains(accounts[i].account.id) {
accounts.remove(at: i) accounts.remove(at: i)
} }
} }
if let _ = immediatePeerId, let intentsAccountId = intentsAccountId {
for account in accounts {
if account.peer.id == intentsAccountId {
maybePrimary = account.account.id
}
}
}
guard let primary = maybePrimary, validAccountIds.contains(primary) else { guard let primary = maybePrimary, validAccountIds.contains(primary) else {
return .fail(.unauthorized) return .fail(.unauthorized)
} }
guard let info = accounts.first(where: { $0.account.id == primary }) else { guard let info = accounts.first(where: { $0.account.id == primary }) else {
return .fail(.unauthorized) return .fail(.unauthorized)
} }
@ -294,17 +316,7 @@ public class ShareRootControllerImpl {
} }
|> then(.single(.done)) |> then(.single(.done))
} }
var immediatePeerId: PeerId?
if #available(iOS 13.0, *), let sendMessageIntent = self?.getExtensionContext()?.intent as? INSendMessageIntent {
if let contact = sendMessageIntent.recipients?.first, let handle = contact.customIdentifier, handle.hasPrefix("tg") {
let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2))
if let userId = Int32(string) {
immediatePeerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
}
}
}
let shareController = ShareController(context: context, subject: .fromExternal({ peerIds, additionalText, account in let shareController = ShareController(context: context, subject: .fromExternal({ peerIds, additionalText, account in
if let strongSelf = self, let inputItems = strongSelf.getExtensionContext()?.inputItems, !inputItems.isEmpty, !peerIds.isEmpty { if let strongSelf = self, let inputItems = strongSelf.getExtensionContext()?.inputItems, !inputItems.isEmpty, !peerIds.isEmpty {
let rawSignals = TGItemProviderSignals.itemSignals(forInputItems: inputItems)! let rawSignals = TGItemProviderSignals.itemSignals(forInputItems: inputItems)!

View File

@ -27,7 +27,7 @@ public struct IntentsSettings: PreferencesEntry, Equatable {
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
self.initiallyReset = decoder.decodeBoolForKey("initiallyReset_v2", orElse: false) self.initiallyReset = decoder.decodeBoolForKey("initiallyReset_v1", orElse: false)
self.account = decoder.decodeOptionalInt64ForKey("account").flatMap { PeerId($0) } self.account = decoder.decodeOptionalInt64ForKey("account").flatMap { PeerId($0) }
self.contacts = decoder.decodeBoolForKey("contacts", orElse: true) self.contacts = decoder.decodeBoolForKey("contacts", orElse: true)
self.privateChats = decoder.decodeBoolForKey("privateChats", orElse: false) self.privateChats = decoder.decodeBoolForKey("privateChats", orElse: false)
@ -37,7 +37,7 @@ public struct IntentsSettings: PreferencesEntry, Equatable {
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
encoder.encodeBool(self.initiallyReset, forKey: "initiallyReset_v2") encoder.encodeBool(self.initiallyReset, forKey: "initiallyReset_v1")
if let account = self.account { if let account = self.account {
encoder.encodeInt64(account.toInt64(), forKey: "account") encoder.encodeInt64(account.toInt64(), forKey: "account")
} else { } else {
@ -62,7 +62,7 @@ public struct IntentsSettings: PreferencesEntry, Equatable {
return lhs.initiallyReset == rhs.initiallyReset && lhs.account == rhs.account && lhs.contacts == rhs.contacts && lhs.privateChats == rhs.privateChats && lhs.savedMessages == rhs.savedMessages && lhs.groups == rhs.groups && lhs.onlyShared == rhs.onlyShared return lhs.initiallyReset == rhs.initiallyReset && lhs.account == rhs.account && lhs.contacts == rhs.contacts && lhs.privateChats == rhs.privateChats && lhs.savedMessages == rhs.savedMessages && lhs.groups == rhs.groups && lhs.onlyShared == rhs.onlyShared
} }
public func withUpdatedAccount(_ account: PeerId) -> IntentsSettings { public func withUpdatedAccount(_ account: PeerId?) -> IntentsSettings {
return IntentsSettings(initiallyReset: self.initiallyReset, account: account, contacts: self.contacts, privateChats: self.privateChats, savedMessages: self.savedMessages, groups: self.groups, onlyShared: self.onlyShared) return IntentsSettings(initiallyReset: self.initiallyReset, account: account, contacts: self.contacts, privateChats: self.privateChats, savedMessages: self.savedMessages, groups: self.groups, onlyShared: self.onlyShared)
} }