mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Add experimental standalone share
This commit is contained in:
parent
7a1cc644a0
commit
eaaade13f2
@ -832,6 +832,709 @@ public final class ShareController: ViewController {
|
|||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var useLegacy = false
|
||||||
|
if self.sharedContext.applicationBindings.isMainApp {
|
||||||
|
useLegacy = true
|
||||||
|
}
|
||||||
|
if peerIds.contains(where: { $0.namespace == Namespaces.Peer.SecretChat }) {
|
||||||
|
useLegacy = true
|
||||||
|
}
|
||||||
|
if let data = self.currentContext.currentAppConfiguration.with({ $0 }).data {
|
||||||
|
if let _ = data["ios_disable_modern_sharing"] {
|
||||||
|
useLegacy = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if useLegacy {
|
||||||
|
return self.shareLegacy(text: text, peerIds: peerIds, topicIds: topicIds, showNames: showNames, silently: silently)
|
||||||
|
} else {
|
||||||
|
return self.shareModern(text: text, peerIds: peerIds, topicIds: topicIds, showNames: showNames, silently: silently)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.controllerNode.shareExternal = { [weak self] _ in
|
||||||
|
if let strongSelf = self {
|
||||||
|
var collectableItems: [CollectableExternalShareItem] = []
|
||||||
|
var subject = strongSelf.subject
|
||||||
|
if let segmentedValues = strongSelf.segmentedValues {
|
||||||
|
let selectedValue = segmentedValues[strongSelf.controllerNode.selectedSegmentedIndex]
|
||||||
|
subject = selectedValue.subject
|
||||||
|
}
|
||||||
|
var messageUrl: String?
|
||||||
|
// var messagesToShare: [Message]?
|
||||||
|
switch subject {
|
||||||
|
case let .url(text):
|
||||||
|
collectableItems.append(CollectableExternalShareItem(url: explicitUrl(text), text: "", author: nil, timestamp: nil, mediaReference: nil))
|
||||||
|
case let .text(string):
|
||||||
|
collectableItems.append(CollectableExternalShareItem(url: "", text: string, author: nil, timestamp: nil, mediaReference: nil))
|
||||||
|
case let .quote(text, url):
|
||||||
|
collectableItems.append(CollectableExternalShareItem(url: "", text: "\"\(text)\"\n\n\(url)", author: nil, timestamp: nil, mediaReference: nil))
|
||||||
|
case let .image(representations):
|
||||||
|
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: Int64.random(in: Int64.min ... Int64.max)), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
||||||
|
collectableItems.append(CollectableExternalShareItem(url: "", text: "", author: nil, timestamp: nil, mediaReference: .standalone(media: media)))
|
||||||
|
case let .media(mediaReference):
|
||||||
|
collectableItems.append(CollectableExternalShareItem(url: "", text: "", author: nil, timestamp: nil, mediaReference: mediaReference))
|
||||||
|
case let .mapMedia(media):
|
||||||
|
let latLong = "\(media.latitude),\(media.longitude)"
|
||||||
|
collectableItems.append(CollectableExternalShareItem(url: "https://maps.apple.com/maps?ll=\(latLong)&q=\(latLong)&t=m", text: "", author: nil, timestamp: nil, mediaReference: nil))
|
||||||
|
case let .messages(messages):
|
||||||
|
// messagesToShare = messages
|
||||||
|
for message in messages {
|
||||||
|
var url: String?
|
||||||
|
var selectedMedia: Media?
|
||||||
|
loop: for media in message.media {
|
||||||
|
switch media {
|
||||||
|
case _ as TelegramMediaImage, _ as TelegramMediaFile:
|
||||||
|
selectedMedia = media
|
||||||
|
break loop
|
||||||
|
case let webpage as TelegramMediaWebpage:
|
||||||
|
if case let .Loaded(content) = webpage.content, ["photo", "document", "video", "gif"].contains(content.type) {
|
||||||
|
if let file = content.file {
|
||||||
|
selectedMedia = file
|
||||||
|
} else if let image = content.image {
|
||||||
|
selectedMedia = image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case _ as TelegramMediaPoll:
|
||||||
|
selectedMedia = media
|
||||||
|
break loop
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let chatPeer = message.peers[message.id.peerId] as? TelegramChannel {
|
||||||
|
if message.id.namespace == Namespaces.Message.Cloud, let addressName = chatPeer.addressName, !addressName.isEmpty {
|
||||||
|
url = "https://t.me/\(addressName)/\(message.id.id)"
|
||||||
|
if messageUrl == nil {
|
||||||
|
messageUrl = url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let accountPeerId = strongSelf.currentAccount.peerId
|
||||||
|
let authorPeerId: PeerId?
|
||||||
|
if let author = message.effectiveAuthor {
|
||||||
|
authorPeerId = author.id
|
||||||
|
} else if message.effectivelyIncoming(accountPeerId) {
|
||||||
|
authorPeerId = message.id.peerId
|
||||||
|
} else {
|
||||||
|
authorPeerId = accountPeerId
|
||||||
|
}
|
||||||
|
|
||||||
|
var restrictedText: String?
|
||||||
|
for attribute in message.attributes {
|
||||||
|
if let attribute = attribute as? RestrictedContentMessageAttribute {
|
||||||
|
restrictedText = attribute.platformText(platform: "ios", contentSettings: strongSelf.currentContext.currentContentSettings.with { $0 }) ?? ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let restrictedText = restrictedText {
|
||||||
|
collectableItems.append(CollectableExternalShareItem(url: url, text: restrictedText, author: authorPeerId, timestamp: message.timestamp, mediaReference: nil))
|
||||||
|
} else {
|
||||||
|
collectableItems.append(CollectableExternalShareItem(url: url, text: message.text, author: authorPeerId, timestamp: message.timestamp, mediaReference: selectedMedia.flatMap({ AnyMediaReference.message(message: MessageReference(message), media: $0) })))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .fromExternal:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return (collectExternalShareItems(strings: strongSelf.presentationData.strings, dateTimeFormat: strongSelf.presentationData.dateTimeFormat, nameOrder: strongSelf.presentationData.nameDisplayOrder, engine: TelegramEngine(account: strongSelf.currentAccount), postbox: strongSelf.currentAccount.postbox, collectableItems: collectableItems, takeOne: !strongSelf.immediateExternalShare)
|
||||||
|
|> deliverOnMainQueue)
|
||||||
|
|> map { state in
|
||||||
|
switch state {
|
||||||
|
case .progress:
|
||||||
|
return .preparing
|
||||||
|
case let .done(items):
|
||||||
|
if let strongSelf = self, !items.isEmpty {
|
||||||
|
strongSelf._ready.set(.single(true))
|
||||||
|
var activityItems: [Any] = []
|
||||||
|
if strongSelf.shareAsLink, let messageUrl = messageUrl, let url = NSURL(string: messageUrl) {
|
||||||
|
activityItems.append(url)
|
||||||
|
} else {
|
||||||
|
for item in items {
|
||||||
|
switch item {
|
||||||
|
case let .url(url):
|
||||||
|
activityItems.append(url as NSURL)
|
||||||
|
case let .text(text):
|
||||||
|
activityItems.append(text as NSString)
|
||||||
|
case let .image(image):
|
||||||
|
activityItems.append(image)
|
||||||
|
case let .file(url, _, _):
|
||||||
|
activityItems.append(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let activities: [UIActivity]? = nil
|
||||||
|
let _ = (strongSelf.didAppearPromise.get()
|
||||||
|
|> filter { $0 }
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
||||||
|
// if asImage, let messages = messagesToShare {
|
||||||
|
// self?.openShareAsImage?(messages)
|
||||||
|
// } else {
|
||||||
|
let activityController = UIActivityViewController(activityItems: activityItems, applicationActivities: activities)
|
||||||
|
if let strongSelf = self, let window = strongSelf.view.window, let rootViewController = window.rootViewController {
|
||||||
|
activityController.popoverPresentationController?.sourceView = window
|
||||||
|
activityController.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: window.bounds.width / 2.0, y: window.bounds.size.height - 1.0), size: CGSize(width: 1.0, height: 1.0))
|
||||||
|
rootViewController.present(activityController, animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return .done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return .single(.done)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.controllerNode.switchToAnotherAccount = { [weak self] in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
strongSelf.controllerNode.animateOut(shared: false, completion: {})
|
||||||
|
|
||||||
|
let presentationData = strongSelf.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
let controller = ActionSheetController(presentationData: presentationData)
|
||||||
|
controller.dismissed = { [weak self] cancelled in
|
||||||
|
if cancelled {
|
||||||
|
self?.controllerNode.animateIn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let dismissAction: () -> Void = { [weak controller] in
|
||||||
|
controller?.dismissAnimated()
|
||||||
|
}
|
||||||
|
var items: [ActionSheetItem] = []
|
||||||
|
for info in strongSelf.switchableAccounts {
|
||||||
|
items.append(ActionSheetPeerItem(context: strongSelf.sharedContext.makeTempAccountContext(account: info.account), peer: EnginePeer(info.peer), title: EnginePeer(info.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), isSelected: info.account.id == strongSelf.currentAccount.id, strings: presentationData.strings, theme: presentationData.theme, action: { [weak self] in
|
||||||
|
dismissAction()
|
||||||
|
self?.switchToAccount(account: info.account, animateIn: true)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
controller.setItemGroups([
|
||||||
|
ActionSheetItemGroup(items: items)
|
||||||
|
])
|
||||||
|
strongSelf.view.endEditing(true)
|
||||||
|
strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
|
}
|
||||||
|
self.controllerNode.debugAction = { [weak self] in
|
||||||
|
self?.debugAction?()
|
||||||
|
}
|
||||||
|
self.displayNodeDidLoad()
|
||||||
|
|
||||||
|
self.peersDisposable.set((self.peers.get()
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] next in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.controllerNode.updatePeers(context: strongSelf.sharedContext.makeTempAccountContext(account: strongSelf.currentAccount), switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
self._ready.set(self.controllerNode.ready.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func loadView() {
|
||||||
|
super.loadView()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func shareModern(text: String, peerIds: [EnginePeer.Id], topicIds: [EnginePeer.Id: Int64], showNames: Bool, silently: Bool) -> Signal<ShareState, ShareControllerError> {
|
||||||
|
return self.currentContext.engine.data.get(EngineDataMap(
|
||||||
|
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))
|
||||||
|
))
|
||||||
|
|> deliverOnMainQueue
|
||||||
|
|> castError(ShareControllerError.self)
|
||||||
|
|> mapToSignal { [weak self] peers -> Signal<ShareState, ShareControllerError> in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
var shareSignals: [Signal<StandaloneSendMessageStatus, StandaloneSendMessagesError>] = []
|
||||||
|
var subject = strongSelf.subject
|
||||||
|
if let segmentedValues = strongSelf.segmentedValues {
|
||||||
|
let selectedValue = segmentedValues[strongSelf.controllerNode.selectedSegmentedIndex]
|
||||||
|
subject = selectedValue.subject
|
||||||
|
}
|
||||||
|
|
||||||
|
func transformMessages(_ messages: [StandaloneSendEnqueueMessage], showNames: Bool, silently: Bool) -> [StandaloneSendEnqueueMessage] {
|
||||||
|
return messages.map { message in
|
||||||
|
var message = message
|
||||||
|
if !showNames {
|
||||||
|
message.forwardOptions = StandaloneSendEnqueueMessage.ForwardOptions(
|
||||||
|
hideNames: true,
|
||||||
|
hideCaptions: false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if silently {
|
||||||
|
message.isSilent = true
|
||||||
|
}
|
||||||
|
return message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch subject {
|
||||||
|
case let .url(url):
|
||||||
|
for peerId in peerIds {
|
||||||
|
guard let maybePeer = peers[peerId], let peer = maybePeer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var banSendText = false
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
|
||||||
|
banSendText = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
|
||||||
|
banSendText = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if banSendText {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyToMessageId: MessageId?
|
||||||
|
if let topicId = topicIds[peerId] {
|
||||||
|
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages: [StandaloneSendEnqueueMessage] = []
|
||||||
|
if !text.isEmpty {
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .text(text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: url + "\n\n" + text,
|
||||||
|
entities: []
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .text(text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: url,
|
||||||
|
entities: []
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
}
|
||||||
|
messages = transformMessages(messages, showNames: showNames, silently: silently)
|
||||||
|
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||||
|
}
|
||||||
|
case let .text(string):
|
||||||
|
for peerId in peerIds {
|
||||||
|
guard let maybePeer = peers[peerId], let peer = maybePeer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var banSendText = false
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
|
||||||
|
banSendText = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
|
||||||
|
banSendText = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if banSendText {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyToMessageId: MessageId?
|
||||||
|
if let topicId = topicIds[peerId] {
|
||||||
|
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages: [StandaloneSendEnqueueMessage] = []
|
||||||
|
if !text.isEmpty {
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .text(text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: text,
|
||||||
|
entities: []
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
}
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .text(text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: string,
|
||||||
|
entities: []
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
messages = transformMessages(messages, showNames: showNames, silently: silently)
|
||||||
|
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||||
|
}
|
||||||
|
case let .quote(string, url):
|
||||||
|
for peerId in peerIds {
|
||||||
|
guard let maybePeer = peers[peerId], let peer = maybePeer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var banSendText = false
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
|
||||||
|
banSendText = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
|
||||||
|
banSendText = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if banSendText {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyToMessageId: MessageId?
|
||||||
|
if let topicId = topicIds[peerId] {
|
||||||
|
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages: [StandaloneSendEnqueueMessage] = []
|
||||||
|
if !text.isEmpty {
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .text(text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: text,
|
||||||
|
entities: []
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
}
|
||||||
|
let attributedText = NSMutableAttributedString(string: string, attributes: [ChatTextInputAttributes.italic: true as NSNumber])
|
||||||
|
attributedText.append(NSAttributedString(string: "\n\n\(url)"))
|
||||||
|
let entities = generateChatInputTextEntities(attributedText)
|
||||||
|
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .text(text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: attributedText.string,
|
||||||
|
entities: entities
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
messages = transformMessages(messages, showNames: showNames, silently: silently)
|
||||||
|
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||||
|
}
|
||||||
|
case let .image(representations):
|
||||||
|
for peerId in peerIds {
|
||||||
|
guard let maybePeer = peers[peerId], let peer = maybePeer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var banSendPhotos = false
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendPhotos) != nil {
|
||||||
|
banSendPhotos = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendPhotos) {
|
||||||
|
banSendPhotos = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if banSendPhotos {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyToMessageId: MessageId?
|
||||||
|
if let topicId = topicIds[peerId] {
|
||||||
|
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages: [StandaloneSendEnqueueMessage] = []
|
||||||
|
|
||||||
|
if let representation = representations.last {
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .image(
|
||||||
|
image: StandaloneSendEnqueueMessage.Image(
|
||||||
|
representation: representation.representation
|
||||||
|
),
|
||||||
|
text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: text,
|
||||||
|
entities: []
|
||||||
|
)
|
||||||
|
),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
}
|
||||||
|
messages = transformMessages(messages, showNames: showNames, silently: silently)
|
||||||
|
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||||
|
}
|
||||||
|
case let .media(mediaReference):
|
||||||
|
var sendTextAsCaption = false
|
||||||
|
if mediaReference.media is TelegramMediaImage || mediaReference.media is TelegramMediaFile {
|
||||||
|
sendTextAsCaption = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for peerId in peerIds {
|
||||||
|
guard let maybePeer = peers[peerId], let peer = maybePeer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var banSendType = false
|
||||||
|
if mediaReference.media is TelegramMediaImage {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendPhotos) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendPhotos) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if let file = mediaReference.media as? TelegramMediaFile {
|
||||||
|
if file.isSticker || file.isAnimated {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendStickers) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendStickers) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if file.isInstantVideo {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendInstantVideos) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendInstantVideos) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if file.isVoice {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendVoice) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendVoice) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if file.isMusic {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendMusic) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendMusic) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if file.isVideo {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendVideos) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendVideos) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendFiles) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendFiles) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if banSendType {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyToMessageId: MessageId?
|
||||||
|
if let topicId = topicIds[peerId] {
|
||||||
|
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages: [StandaloneSendEnqueueMessage] = []
|
||||||
|
if !text.isEmpty && !sendTextAsCaption {
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .text(text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: text,
|
||||||
|
entities: []
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .arbitraryMedia(
|
||||||
|
media: mediaReference,
|
||||||
|
text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: sendTextAsCaption ? text : "",
|
||||||
|
entities: []
|
||||||
|
)
|
||||||
|
),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
messages = transformMessages(messages, showNames: showNames, silently: silently)
|
||||||
|
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||||
|
}
|
||||||
|
case let .mapMedia(media):
|
||||||
|
for peerId in peerIds {
|
||||||
|
guard let maybePeer = peers[peerId], let peer = maybePeer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var banSendText = false
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
|
||||||
|
banSendText = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
|
||||||
|
banSendText = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if banSendText {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyToMessageId: MessageId?
|
||||||
|
if let topicId = topicIds[peerId] {
|
||||||
|
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
|
||||||
|
}
|
||||||
|
|
||||||
|
var messages: [StandaloneSendEnqueueMessage] = []
|
||||||
|
if !text.isEmpty {
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .text(text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: text,
|
||||||
|
entities: []
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
messages.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .map(map: media),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
messages = transformMessages(messages, showNames: showNames, silently: silently)
|
||||||
|
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
|
||||||
|
}
|
||||||
|
case let .messages(messages):
|
||||||
|
for peerId in peerIds {
|
||||||
|
guard let maybePeer = peers[peerId], let peer = maybePeer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyToMessageId: MessageId?
|
||||||
|
var threadId: Int64?
|
||||||
|
if let topicId = topicIds[peerId] {
|
||||||
|
replyToMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: Int32(clamping: topicId))
|
||||||
|
threadId = topicId
|
||||||
|
}
|
||||||
|
|
||||||
|
var messagesToEnqueue: [StandaloneSendEnqueueMessage] = []
|
||||||
|
if !text.isEmpty {
|
||||||
|
var banSendText = false
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendText) != nil {
|
||||||
|
banSendText = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendText) {
|
||||||
|
banSendText = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if banSendText {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
|
||||||
|
messagesToEnqueue.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .text(text: StandaloneSendEnqueueMessage.Text(
|
||||||
|
string: text,
|
||||||
|
entities: []
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
}
|
||||||
|
for message in messages {
|
||||||
|
for media in message.media {
|
||||||
|
var banSendType = false
|
||||||
|
if media is TelegramMediaImage {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendPhotos) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendPhotos) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if let file = media as? TelegramMediaFile {
|
||||||
|
if file.isSticker || file.isAnimated {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendStickers) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendStickers) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if file.isInstantVideo {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendInstantVideos) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendInstantVideos) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if file.isVoice {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendVoice) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendVoice) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if file.isMusic {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendMusic) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendMusic) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else if file.isVideo {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendVideos) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendVideos) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if case let .channel(channel) = peer, channel.hasBannedPermission(.banSendFiles) != nil {
|
||||||
|
banSendType = true
|
||||||
|
} else if case let .legacyGroup(group) = peer, group.hasBannedPermission(.banSendFiles) {
|
||||||
|
banSendType = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if banSendType {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
|
||||||
|
return .fail(.generic)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
messagesToEnqueue.append(StandaloneSendEnqueueMessage(
|
||||||
|
content: .forward(forward: StandaloneSendEnqueueMessage.Forward(
|
||||||
|
sourceId: message.id,
|
||||||
|
threadId: threadId
|
||||||
|
)),
|
||||||
|
replyToMessageId: replyToMessageId
|
||||||
|
))
|
||||||
|
}
|
||||||
|
messagesToEnqueue = transformMessages(messagesToEnqueue, showNames: showNames, silently: silently)
|
||||||
|
shareSignals.append(standaloneSendEnqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue))
|
||||||
|
}
|
||||||
|
case let .fromExternal(f):
|
||||||
|
return f(peerIds, topicIds, text, strongSelf.currentAccount, silently)
|
||||||
|
|> map { state -> ShareState in
|
||||||
|
switch state {
|
||||||
|
case let .preparing(long):
|
||||||
|
return .preparing(long)
|
||||||
|
case let .progress(value):
|
||||||
|
return .progress(value)
|
||||||
|
case .done:
|
||||||
|
return .done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let account = strongSelf.currentAccount
|
||||||
|
let queue = Queue.mainQueue()
|
||||||
|
//var displayedError = false
|
||||||
|
return combineLatest(queue: queue, shareSignals)
|
||||||
|
|> `catch` { error -> Signal<[StandaloneSendMessageStatus], ShareControllerError> in
|
||||||
|
Queue.mainQueue().async {
|
||||||
|
let _ = (TelegramEngine(account: account).data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: error.peerId))
|
||||||
|
|> deliverOnMainQueue).start(next: { peer in
|
||||||
|
guard let strongSelf = self, let peer = peer else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if case .slowmodeActive = error.reason {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: strongSelf.presentationData.strings.Chat_SlowmodeSendError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
} else if case .mediaRestricted = error.reason {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder), text: restrictedSendingContentsText(peer: peer, presentationData: strongSelf.presentationData), actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return .single([])
|
||||||
|
}
|
||||||
|
|> mapToSignal { progressSets -> Signal<ShareState, ShareControllerError> in
|
||||||
|
if progressSets.isEmpty {
|
||||||
|
return .single(.done)
|
||||||
|
}
|
||||||
|
for item in progressSets {
|
||||||
|
if case .progress = item {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return .single(.done)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func shareLegacy(text: String, peerIds: [EnginePeer.Id], topicIds: [EnginePeer.Id: Int64], showNames: Bool, silently: Bool) -> Signal<ShareState, ShareControllerError> {
|
||||||
return self.currentContext.engine.data.get(EngineDataMap(
|
return self.currentContext.engine.data.get(EngineDataMap(
|
||||||
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))
|
peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))
|
||||||
))
|
))
|
||||||
@ -1260,187 +1963,6 @@ public final class ShareController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.controllerNode.shareExternal = { [weak self] _ in
|
|
||||||
if let strongSelf = self {
|
|
||||||
var collectableItems: [CollectableExternalShareItem] = []
|
|
||||||
var subject = strongSelf.subject
|
|
||||||
if let segmentedValues = strongSelf.segmentedValues {
|
|
||||||
let selectedValue = segmentedValues[strongSelf.controllerNode.selectedSegmentedIndex]
|
|
||||||
subject = selectedValue.subject
|
|
||||||
}
|
|
||||||
var messageUrl: String?
|
|
||||||
// var messagesToShare: [Message]?
|
|
||||||
switch subject {
|
|
||||||
case let .url(text):
|
|
||||||
collectableItems.append(CollectableExternalShareItem(url: explicitUrl(text), text: "", author: nil, timestamp: nil, mediaReference: nil))
|
|
||||||
case let .text(string):
|
|
||||||
collectableItems.append(CollectableExternalShareItem(url: "", text: string, author: nil, timestamp: nil, mediaReference: nil))
|
|
||||||
case let .quote(text, url):
|
|
||||||
collectableItems.append(CollectableExternalShareItem(url: "", text: "\"\(text)\"\n\n\(url)", author: nil, timestamp: nil, mediaReference: nil))
|
|
||||||
case let .image(representations):
|
|
||||||
let media = TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: Int64.random(in: Int64.min ... Int64.max)), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil, flags: [])
|
|
||||||
collectableItems.append(CollectableExternalShareItem(url: "", text: "", author: nil, timestamp: nil, mediaReference: .standalone(media: media)))
|
|
||||||
case let .media(mediaReference):
|
|
||||||
collectableItems.append(CollectableExternalShareItem(url: "", text: "", author: nil, timestamp: nil, mediaReference: mediaReference))
|
|
||||||
case let .mapMedia(media):
|
|
||||||
let latLong = "\(media.latitude),\(media.longitude)"
|
|
||||||
collectableItems.append(CollectableExternalShareItem(url: "https://maps.apple.com/maps?ll=\(latLong)&q=\(latLong)&t=m", text: "", author: nil, timestamp: nil, mediaReference: nil))
|
|
||||||
case let .messages(messages):
|
|
||||||
// messagesToShare = messages
|
|
||||||
for message in messages {
|
|
||||||
var url: String?
|
|
||||||
var selectedMedia: Media?
|
|
||||||
loop: for media in message.media {
|
|
||||||
switch media {
|
|
||||||
case _ as TelegramMediaImage, _ as TelegramMediaFile:
|
|
||||||
selectedMedia = media
|
|
||||||
break loop
|
|
||||||
case let webpage as TelegramMediaWebpage:
|
|
||||||
if case let .Loaded(content) = webpage.content, ["photo", "document", "video", "gif"].contains(content.type) {
|
|
||||||
if let file = content.file {
|
|
||||||
selectedMedia = file
|
|
||||||
} else if let image = content.image {
|
|
||||||
selectedMedia = image
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case _ as TelegramMediaPoll:
|
|
||||||
selectedMedia = media
|
|
||||||
break loop
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let chatPeer = message.peers[message.id.peerId] as? TelegramChannel {
|
|
||||||
if message.id.namespace == Namespaces.Message.Cloud, let addressName = chatPeer.addressName, !addressName.isEmpty {
|
|
||||||
url = "https://t.me/\(addressName)/\(message.id.id)"
|
|
||||||
if messageUrl == nil {
|
|
||||||
messageUrl = url
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let accountPeerId = strongSelf.currentAccount.peerId
|
|
||||||
let authorPeerId: PeerId?
|
|
||||||
if let author = message.effectiveAuthor {
|
|
||||||
authorPeerId = author.id
|
|
||||||
} else if message.effectivelyIncoming(accountPeerId) {
|
|
||||||
authorPeerId = message.id.peerId
|
|
||||||
} else {
|
|
||||||
authorPeerId = accountPeerId
|
|
||||||
}
|
|
||||||
|
|
||||||
var restrictedText: String?
|
|
||||||
for attribute in message.attributes {
|
|
||||||
if let attribute = attribute as? RestrictedContentMessageAttribute {
|
|
||||||
restrictedText = attribute.platformText(platform: "ios", contentSettings: strongSelf.currentContext.currentContentSettings.with { $0 }) ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let restrictedText = restrictedText {
|
|
||||||
collectableItems.append(CollectableExternalShareItem(url: url, text: restrictedText, author: authorPeerId, timestamp: message.timestamp, mediaReference: nil))
|
|
||||||
} else {
|
|
||||||
collectableItems.append(CollectableExternalShareItem(url: url, text: message.text, author: authorPeerId, timestamp: message.timestamp, mediaReference: selectedMedia.flatMap({ AnyMediaReference.message(message: MessageReference(message), media: $0) })))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case .fromExternal:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return (collectExternalShareItems(strings: strongSelf.presentationData.strings, dateTimeFormat: strongSelf.presentationData.dateTimeFormat, nameOrder: strongSelf.presentationData.nameDisplayOrder, engine: TelegramEngine(account: strongSelf.currentAccount), postbox: strongSelf.currentAccount.postbox, collectableItems: collectableItems, takeOne: !strongSelf.immediateExternalShare)
|
|
||||||
|> deliverOnMainQueue)
|
|
||||||
|> map { state in
|
|
||||||
switch state {
|
|
||||||
case .progress:
|
|
||||||
return .preparing
|
|
||||||
case let .done(items):
|
|
||||||
if let strongSelf = self, !items.isEmpty {
|
|
||||||
strongSelf._ready.set(.single(true))
|
|
||||||
var activityItems: [Any] = []
|
|
||||||
if strongSelf.shareAsLink, let messageUrl = messageUrl, let url = NSURL(string: messageUrl) {
|
|
||||||
activityItems.append(url)
|
|
||||||
} else {
|
|
||||||
for item in items {
|
|
||||||
switch item {
|
|
||||||
case let .url(url):
|
|
||||||
activityItems.append(url as NSURL)
|
|
||||||
case let .text(text):
|
|
||||||
activityItems.append(text as NSString)
|
|
||||||
case let .image(image):
|
|
||||||
activityItems.append(image)
|
|
||||||
case let .file(url, _, _):
|
|
||||||
activityItems.append(url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let activities: [UIActivity]? = nil
|
|
||||||
let _ = (strongSelf.didAppearPromise.get()
|
|
||||||
|> filter { $0 }
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] _ in
|
|
||||||
// if asImage, let messages = messagesToShare {
|
|
||||||
// self?.openShareAsImage?(messages)
|
|
||||||
// } else {
|
|
||||||
let activityController = UIActivityViewController(activityItems: activityItems, applicationActivities: activities)
|
|
||||||
if let strongSelf = self, let window = strongSelf.view.window, let rootViewController = window.rootViewController {
|
|
||||||
activityController.popoverPresentationController?.sourceView = window
|
|
||||||
activityController.popoverPresentationController?.sourceRect = CGRect(origin: CGPoint(x: window.bounds.width / 2.0, y: window.bounds.size.height - 1.0), size: CGSize(width: 1.0, height: 1.0))
|
|
||||||
rootViewController.present(activityController, animated: true, completion: nil)
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return .done
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return .single(.done)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.controllerNode.switchToAnotherAccount = { [weak self] in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
strongSelf.controllerNode.animateOut(shared: false, completion: {})
|
|
||||||
|
|
||||||
let presentationData = strongSelf.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
let controller = ActionSheetController(presentationData: presentationData)
|
|
||||||
controller.dismissed = { [weak self] cancelled in
|
|
||||||
if cancelled {
|
|
||||||
self?.controllerNode.animateIn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let dismissAction: () -> Void = { [weak controller] in
|
|
||||||
controller?.dismissAnimated()
|
|
||||||
}
|
|
||||||
var items: [ActionSheetItem] = []
|
|
||||||
for info in strongSelf.switchableAccounts {
|
|
||||||
items.append(ActionSheetPeerItem(context: strongSelf.sharedContext.makeTempAccountContext(account: info.account), peer: EnginePeer(info.peer), title: EnginePeer(info.peer).displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), isSelected: info.account.id == strongSelf.currentAccount.id, strings: presentationData.strings, theme: presentationData.theme, action: { [weak self] in
|
|
||||||
dismissAction()
|
|
||||||
self?.switchToAccount(account: info.account, animateIn: true)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
controller.setItemGroups([
|
|
||||||
ActionSheetItemGroup(items: items)
|
|
||||||
])
|
|
||||||
strongSelf.view.endEditing(true)
|
|
||||||
strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
|
||||||
}
|
|
||||||
self.controllerNode.debugAction = { [weak self] in
|
|
||||||
self?.debugAction?()
|
|
||||||
}
|
|
||||||
self.displayNodeDidLoad()
|
|
||||||
|
|
||||||
self.peersDisposable.set((self.peers.get()
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] next in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.controllerNode.updatePeers(context: strongSelf.sharedContext.makeTempAccountContext(account: strongSelf.currentAccount), switchableAccounts: strongSelf.switchableAccounts, peers: next.0, accountPeer: next.1, defaultAction: strongSelf.defaultAction)
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
self._ready.set(self.controllerNode.ready.get())
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func loadView() {
|
|
||||||
super.loadView()
|
|
||||||
}
|
|
||||||
|
|
||||||
let didAppearPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
|
let didAppearPromise = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||||
override public func viewDidAppear(_ animated: Bool) {
|
override public func viewDidAppear(_ animated: Bool) {
|
||||||
|
@ -24,6 +24,426 @@ public enum StandaloneSendMessageError {
|
|||||||
case generic
|
case generic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum StandaloneSendMessageStatus {
|
||||||
|
case progress(Float)
|
||||||
|
case done
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct StandaloneSendMessagesError {
|
||||||
|
public var peerId: PeerId
|
||||||
|
public var reason: PendingMessageFailureReason?
|
||||||
|
|
||||||
|
init(
|
||||||
|
peerId: PeerId,
|
||||||
|
reason: PendingMessageFailureReason?
|
||||||
|
) {
|
||||||
|
self.peerId = peerId
|
||||||
|
self.reason = reason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct StandaloneSendEnqueueMessage {
|
||||||
|
public struct Text {
|
||||||
|
public var string: String
|
||||||
|
public var entities: [MessageTextEntity]
|
||||||
|
|
||||||
|
public init(
|
||||||
|
string: String,
|
||||||
|
entities: [MessageTextEntity]
|
||||||
|
) {
|
||||||
|
self.string = string
|
||||||
|
self.entities = entities
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Image {
|
||||||
|
public var representation: TelegramMediaImageRepresentation
|
||||||
|
|
||||||
|
public init(
|
||||||
|
representation: TelegramMediaImageRepresentation
|
||||||
|
) {
|
||||||
|
self.representation = representation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct Forward {
|
||||||
|
public var sourceId: MessageId
|
||||||
|
public var threadId: Int64?
|
||||||
|
|
||||||
|
public init(
|
||||||
|
sourceId: MessageId,
|
||||||
|
threadId: Int64?
|
||||||
|
) {
|
||||||
|
self.sourceId = sourceId
|
||||||
|
self.threadId = threadId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ForwardOptions {
|
||||||
|
public var hideNames: Bool
|
||||||
|
public var hideCaptions: Bool
|
||||||
|
|
||||||
|
public init(
|
||||||
|
hideNames: Bool,
|
||||||
|
hideCaptions: Bool
|
||||||
|
) {
|
||||||
|
self.hideNames = hideNames
|
||||||
|
self.hideCaptions = hideCaptions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Content {
|
||||||
|
case text(text: Text)
|
||||||
|
case image(image: Image, text: Text)
|
||||||
|
case map(map: TelegramMediaMap)
|
||||||
|
case arbitraryMedia(media: AnyMediaReference, text: Text)
|
||||||
|
case forward(forward: Forward)
|
||||||
|
}
|
||||||
|
|
||||||
|
public var content: Content
|
||||||
|
public var replyToMessageId: MessageId?
|
||||||
|
public var forwardOptions: ForwardOptions?
|
||||||
|
public var isSilent: Bool = false
|
||||||
|
|
||||||
|
public init(
|
||||||
|
content: Content,
|
||||||
|
replyToMessageId: MessageId?
|
||||||
|
) {
|
||||||
|
self.content = content
|
||||||
|
self.replyToMessageId = replyToMessageId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func standaloneSendEnqueueMessages(account: Account, peerId: PeerId, messages: [StandaloneSendEnqueueMessage]) -> Signal<StandaloneSendMessageStatus, StandaloneSendMessagesError> {
|
||||||
|
#if !DEBUG
|
||||||
|
error
|
||||||
|
#endif
|
||||||
|
|
||||||
|
let signals: [Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>] = messages.map { message in
|
||||||
|
var attributes: [MessageAttribute] = []
|
||||||
|
var text: String = ""
|
||||||
|
var media: [Media] = []
|
||||||
|
|
||||||
|
switch message.content {
|
||||||
|
case let .text(textValue):
|
||||||
|
text = textValue.string
|
||||||
|
if !textValue.entities.isEmpty {
|
||||||
|
attributes.append(TextEntitiesMessageAttribute(entities: textValue.entities))
|
||||||
|
}
|
||||||
|
case let .image(image, textValue):
|
||||||
|
media.append(TelegramMediaImage(
|
||||||
|
imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: MediaId.Id.random(in: Int64.min ... Int64.max)),
|
||||||
|
representations: [image.representation],
|
||||||
|
immediateThumbnailData: nil,
|
||||||
|
reference: nil,
|
||||||
|
partialReference: nil,
|
||||||
|
flags: []
|
||||||
|
))
|
||||||
|
|
||||||
|
text = textValue.string
|
||||||
|
if !textValue.entities.isEmpty {
|
||||||
|
attributes.append(TextEntitiesMessageAttribute(entities: textValue.entities))
|
||||||
|
}
|
||||||
|
case let .map(mapValue):
|
||||||
|
media.append(mapValue)
|
||||||
|
case let .arbitraryMedia(mediaValue, textValue):
|
||||||
|
media.append(mediaValue.media)
|
||||||
|
|
||||||
|
text = textValue.string
|
||||||
|
if !textValue.entities.isEmpty {
|
||||||
|
attributes.append(TextEntitiesMessageAttribute(entities: textValue.entities))
|
||||||
|
}
|
||||||
|
case let .forward(forwardValue):
|
||||||
|
attributes.append(ForwardSourceInfoAttribute(messageId: forwardValue.sourceId))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let replyToMessageId = message.replyToMessageId {
|
||||||
|
attributes.append(ReplyMessageAttribute(messageId: replyToMessageId, threadMessageId: nil))
|
||||||
|
}
|
||||||
|
if let forwardOptions = message.forwardOptions {
|
||||||
|
attributes.append(ForwardOptionsMessageAttribute(hideNames: forwardOptions.hideNames, hideCaptions: forwardOptions.hideCaptions))
|
||||||
|
}
|
||||||
|
if message.isSilent {
|
||||||
|
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = messageContentToUpload(accountPeerId: account.peerId, network: account.network, postbox: account.postbox, auxiliaryMethods: account.auxiliaryMethods, transformOutgoingMessageMedia: account.transformOutgoingMessageMedia, messageMediaPreuploadManager: account.messageMediaPreuploadManager, revalidationContext: account.mediaReferenceRevalidationContext, forceReupload: false, isGrouped: false, passFetchProgress: true, forceNoBigParts: false, peerId: peerId, messageId: nil, attributes: attributes, text: text, media: media)
|
||||||
|
let contentResult: Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>
|
||||||
|
switch content {
|
||||||
|
case let .signal(value, _):
|
||||||
|
contentResult = value
|
||||||
|
case let .immediate(value, _):
|
||||||
|
contentResult = .single(value)
|
||||||
|
}
|
||||||
|
return contentResult
|
||||||
|
}
|
||||||
|
|
||||||
|
return combineLatest(signals)
|
||||||
|
|> mapError { _ -> StandaloneSendMessagesError in
|
||||||
|
return StandaloneSendMessagesError(peerId: peerId, reason: nil)
|
||||||
|
}
|
||||||
|
|> mapToSignal { contentResults -> Signal<StandaloneSendMessageStatus, StandaloneSendMessagesError> in
|
||||||
|
var progressSum: Float = 0.0
|
||||||
|
var allResults: [PendingMessageUploadedContentAndReuploadInfo] = []
|
||||||
|
var allDone = true
|
||||||
|
for status in contentResults {
|
||||||
|
switch status {
|
||||||
|
case let .progress(value):
|
||||||
|
allDone = false
|
||||||
|
progressSum += value
|
||||||
|
case let .content(content):
|
||||||
|
allResults.append(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if allDone {
|
||||||
|
var sendSignals: [Signal<Never, StandaloneSendMessagesError>] = []
|
||||||
|
sendSignals.removeAll()
|
||||||
|
|
||||||
|
for content in allResults {
|
||||||
|
switch content.content {
|
||||||
|
case let .text(text):
|
||||||
|
let _ = text
|
||||||
|
preconditionFailure()
|
||||||
|
case let .media(inputMedia, text):
|
||||||
|
let _ = inputMedia
|
||||||
|
let _ = text
|
||||||
|
preconditionFailure()
|
||||||
|
case let .forward(source):
|
||||||
|
let _ = source
|
||||||
|
preconditionFailure()
|
||||||
|
case let .chatContextResult(result):
|
||||||
|
let _ = result
|
||||||
|
preconditionFailure()
|
||||||
|
case let .secretMedia(inputFile, size, key):
|
||||||
|
let _ = inputFile
|
||||||
|
let _ = size
|
||||||
|
let _ = key
|
||||||
|
preconditionFailure()
|
||||||
|
case .messageScreenshot:
|
||||||
|
return .single(.done)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return combineLatest(sendSignals)
|
||||||
|
|> ignoreValues
|
||||||
|
|> map { _ -> StandaloneSendMessageStatus in
|
||||||
|
}
|
||||||
|
|> then(.single(.done))
|
||||||
|
} else {
|
||||||
|
return .single(.progress(progressSum / max(1.0, Float(contentResults.count))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func sendUploadedMessageContent(postbox: Postbox, network: Network, stateManager: AccountStateManager, accountPeerId: PeerId, peerId: PeerId, content: PendingMessageUploadedContentAndReuploadInfo, text: String, attributes: [MessageAttribute], threadId: Int64?) -> Signal<Never, StandaloneSendMessagesError> {
|
||||||
|
return postbox.transaction { transaction -> Signal<Never, StandaloneSendMessagesError> in
|
||||||
|
if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
|
assertionFailure()
|
||||||
|
//PendingMessageManager.sendSecretMessageContent(transaction: transaction, message: message, content: content)
|
||||||
|
return .complete()
|
||||||
|
} else if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
|
||||||
|
var uniqueId: Int64 = 0
|
||||||
|
var forwardSourceInfoAttribute: ForwardSourceInfoAttribute?
|
||||||
|
var messageEntities: [Api.MessageEntity]?
|
||||||
|
var replyMessageId: Int32?
|
||||||
|
var replyToStoryId: StoryId?
|
||||||
|
var scheduleTime: Int32?
|
||||||
|
var sendAsPeerId: PeerId?
|
||||||
|
var bubbleUpEmojiOrStickersets = false
|
||||||
|
|
||||||
|
var flags: Int32 = 0
|
||||||
|
|
||||||
|
for attribute in attributes {
|
||||||
|
if let replyAttribute = attribute as? ReplyMessageAttribute {
|
||||||
|
replyMessageId = replyAttribute.messageId.id
|
||||||
|
} else if let attribute = attribute as? ReplyStoryAttribute {
|
||||||
|
replyToStoryId = attribute.storyId
|
||||||
|
} else if let outgoingInfo = attribute as? OutgoingMessageInfoAttribute {
|
||||||
|
uniqueId = outgoingInfo.uniqueId
|
||||||
|
bubbleUpEmojiOrStickersets = !outgoingInfo.bubbleUpEmojiOrStickersets.isEmpty
|
||||||
|
} else if let attribute = attribute as? ForwardSourceInfoAttribute {
|
||||||
|
forwardSourceInfoAttribute = attribute
|
||||||
|
} else if let attribute = attribute as? TextEntitiesMessageAttribute {
|
||||||
|
var associatedPeers = SimpleDictionary<PeerId, Peer>()
|
||||||
|
for attributePeerId in attribute.associatedPeerIds {
|
||||||
|
if let peer = transaction.getPeer(attributePeerId) {
|
||||||
|
associatedPeers[peer.id] = peer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
messageEntities = apiTextAttributeEntities(attribute, associatedPeers: associatedPeers)
|
||||||
|
} else if let attribute = attribute as? OutgoingContentInfoMessageAttribute {
|
||||||
|
if attribute.flags.contains(.disableLinkPreviews) {
|
||||||
|
flags |= Int32(1 << 1)
|
||||||
|
}
|
||||||
|
} else if let attribute = attribute as? NotificationInfoMessageAttribute {
|
||||||
|
if attribute.flags.contains(.muted) {
|
||||||
|
flags |= Int32(1 << 5)
|
||||||
|
}
|
||||||
|
} else if let attribute = attribute as? OutgoingScheduleInfoMessageAttribute {
|
||||||
|
flags |= Int32(1 << 10)
|
||||||
|
scheduleTime = attribute.scheduleTime
|
||||||
|
} else if let attribute = attribute as? SendAsMessageAttribute {
|
||||||
|
sendAsPeerId = attribute.peerId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if case .forward = content.content {
|
||||||
|
} else {
|
||||||
|
flags |= (1 << 7)
|
||||||
|
|
||||||
|
if let _ = replyMessageId {
|
||||||
|
flags |= Int32(1 << 0)
|
||||||
|
}
|
||||||
|
if let _ = messageEntities {
|
||||||
|
flags |= Int32(1 << 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sendAsInputPeer: Api.InputPeer?
|
||||||
|
if let sendAsPeerId = sendAsPeerId, let sendAsPeer = transaction.getPeer(sendAsPeerId), let inputPeer = apiInputPeerOrSelf(sendAsPeer, accountPeerId: accountPeerId) {
|
||||||
|
sendAsInputPeer = inputPeer
|
||||||
|
flags |= (1 << 13)
|
||||||
|
}
|
||||||
|
|
||||||
|
let dependencyTag: PendingMessageRequestDependencyTag? = nil//(messageId: messageId)
|
||||||
|
|
||||||
|
let sendMessageRequest: Signal<NetworkRequestResult<Api.Updates>, MTRpcError>
|
||||||
|
switch content.content {
|
||||||
|
case .text:
|
||||||
|
if bubbleUpEmojiOrStickersets {
|
||||||
|
flags |= Int32(1 << 15)
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyTo: Api.InputReplyTo?
|
||||||
|
if let replyMessageId = replyMessageId {
|
||||||
|
flags |= 1 << 0
|
||||||
|
|
||||||
|
var replyFlags: Int32 = 0
|
||||||
|
if threadId != nil {
|
||||||
|
replyFlags |= 1 << 0
|
||||||
|
}
|
||||||
|
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: replyMessageId, topMsgId: threadId.flatMap(Int32.init(clamping:)))
|
||||||
|
} else if let replyToStoryId = replyToStoryId {
|
||||||
|
if let inputUser = transaction.getPeer(replyToStoryId.peerId).flatMap(apiInputUser) {
|
||||||
|
flags |= 1 << 0
|
||||||
|
replyTo = .inputReplyToStory(userId: inputUser, storyId: replyToStoryId.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), info: .acknowledgement, tag: dependencyTag)
|
||||||
|
case let .media(inputMedia, text):
|
||||||
|
if bubbleUpEmojiOrStickersets {
|
||||||
|
flags |= Int32(1 << 15)
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyTo: Api.InputReplyTo?
|
||||||
|
if let replyMessageId = replyMessageId {
|
||||||
|
flags |= 1 << 0
|
||||||
|
|
||||||
|
var replyFlags: Int32 = 0
|
||||||
|
if threadId != nil {
|
||||||
|
replyFlags |= 1 << 0
|
||||||
|
}
|
||||||
|
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: replyMessageId, topMsgId: threadId.flatMap(Int32.init(clamping:)))
|
||||||
|
} else if let replyToStoryId = replyToStoryId {
|
||||||
|
if let inputUser = transaction.getPeer(replyToStoryId.peerId).flatMap(apiInputUser) {
|
||||||
|
flags |= 1 << 0
|
||||||
|
replyTo = .inputReplyToStory(userId: inputUser, storyId: replyToStoryId.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), tag: dependencyTag)
|
||||||
|
|> map(NetworkRequestResult.result)
|
||||||
|
case let .forward(sourceInfo):
|
||||||
|
var topMsgId: Int32?
|
||||||
|
if let threadId = threadId {
|
||||||
|
flags |= Int32(1 << 9)
|
||||||
|
topMsgId = Int32(clamping: threadId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let forwardSourceInfoAttribute = forwardSourceInfoAttribute, let sourcePeer = transaction.getPeer(forwardSourceInfoAttribute.messageId.peerId), let sourceInputPeer = apiInputPeer(sourcePeer) {
|
||||||
|
sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer, topMsgId: topMsgId, scheduleDate: scheduleTime, sendAs: sendAsInputPeer), tag: dependencyTag)
|
||||||
|
|> map(NetworkRequestResult.result)
|
||||||
|
} else {
|
||||||
|
sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "internal"))
|
||||||
|
}
|
||||||
|
case let .chatContextResult(chatContextResult):
|
||||||
|
if chatContextResult.hideVia {
|
||||||
|
flags |= Int32(1 << 11)
|
||||||
|
}
|
||||||
|
|
||||||
|
var replyTo: Api.InputReplyTo?
|
||||||
|
if let replyMessageId = replyMessageId {
|
||||||
|
flags |= 1 << 0
|
||||||
|
|
||||||
|
var replyFlags: Int32 = 0
|
||||||
|
if threadId != nil {
|
||||||
|
replyFlags |= 1 << 0
|
||||||
|
}
|
||||||
|
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: replyMessageId, topMsgId: threadId.flatMap(Int32.init(clamping:)))
|
||||||
|
} else if let replyToStoryId = replyToStoryId {
|
||||||
|
if let inputUser = transaction.getPeer(replyToStoryId.peerId).flatMap(apiInputUser) {
|
||||||
|
flags |= 1 << 0
|
||||||
|
replyTo = .inputReplyToStory(userId: inputUser, storyId: replyToStoryId.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessageRequest = network.request(Api.functions.messages.sendInlineBotResult(flags: flags, peer: inputPeer, replyTo: replyTo, randomId: uniqueId, queryId: chatContextResult.queryId, id: chatContextResult.id, scheduleDate: scheduleTime, sendAs: sendAsInputPeer))
|
||||||
|
|> map(NetworkRequestResult.result)
|
||||||
|
case .messageScreenshot:
|
||||||
|
let replyTo: Api.InputReplyTo
|
||||||
|
|
||||||
|
if let replyMessageId = replyMessageId {
|
||||||
|
let replyFlags: Int32 = 0
|
||||||
|
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: replyMessageId, topMsgId: nil)
|
||||||
|
} else if let replyToStoryId = replyToStoryId {
|
||||||
|
if let inputUser = transaction.getPeer(replyToStoryId.peerId).flatMap(apiInputUser) {
|
||||||
|
flags |= 1 << 0
|
||||||
|
replyTo = .inputReplyToStory(userId: inputUser, storyId: replyToStoryId.id)
|
||||||
|
} else {
|
||||||
|
let replyFlags: Int32 = 0
|
||||||
|
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: 0, topMsgId: nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let replyFlags: Int32 = 0
|
||||||
|
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: 0, topMsgId: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessageRequest = network.request(Api.functions.messages.sendScreenshotNotification(peer: inputPeer, replyTo: replyTo, randomId: uniqueId))
|
||||||
|
|> map(NetworkRequestResult.result)
|
||||||
|
case .secretMedia:
|
||||||
|
assertionFailure()
|
||||||
|
sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "internal"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendMessageRequest
|
||||||
|
|> mapToSignal { result -> Signal<Never, MTRpcError> in
|
||||||
|
switch result {
|
||||||
|
case .progress:
|
||||||
|
return .complete()
|
||||||
|
case .acknowledged:
|
||||||
|
return .complete()
|
||||||
|
case let .result(result):
|
||||||
|
stateManager.addUpdates(result)
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> mapError { error -> StandaloneSendMessagesError in
|
||||||
|
if error.errorDescription.hasPrefix("FILEREF_INVALID") || error.errorDescription.hasPrefix("FILE_REFERENCE_") {
|
||||||
|
return StandaloneSendMessagesError(peerId: peerId, reason: nil)
|
||||||
|
} else if let failureReason = sendMessageReasonForError(error.errorDescription) {
|
||||||
|
return StandaloneSendMessagesError(peerId: peerId, reason: failureReason)
|
||||||
|
}
|
||||||
|
return StandaloneSendMessagesError(peerId: peerId, reason: nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> castError(StandaloneSendMessagesError.self)
|
||||||
|
|> switchToLatest
|
||||||
|
}
|
||||||
|
|
||||||
public func standaloneSendMessage(account: Account, peerId: PeerId, text: String, attributes: [MessageAttribute], media: StandaloneMedia?, replyToMessageId: MessageId?) -> Signal<Float, StandaloneSendMessageError> {
|
public func standaloneSendMessage(account: Account, peerId: PeerId, text: String, attributes: [MessageAttribute], media: StandaloneMedia?, replyToMessageId: MessageId?) -> Signal<Float, StandaloneSendMessageError> {
|
||||||
let content: Signal<StandaloneSendMessageEvent, StandaloneSendMessageError>
|
let content: Signal<StandaloneSendMessageEvent, StandaloneSendMessageError>
|
||||||
if let media = media {
|
if let media = media {
|
||||||
|
@ -60,7 +60,7 @@ public enum PendingMessageFailureReason {
|
|||||||
case sendingTooFast
|
case sendingTooFast
|
||||||
}
|
}
|
||||||
|
|
||||||
private func reasonForError(_ error: String) -> PendingMessageFailureReason? {
|
func sendMessageReasonForError(_ error: String) -> PendingMessageFailureReason? {
|
||||||
if error.hasPrefix("PEER_FLOOD") {
|
if error.hasPrefix("PEER_FLOOD") {
|
||||||
return .flood
|
return .flood
|
||||||
} else if error.hasPrefix("SENDING_TOO_FAST") {
|
} else if error.hasPrefix("SENDING_TOO_FAST") {
|
||||||
@ -125,7 +125,7 @@ private func failMessages(postbox: Postbox, ids: [MessageId]) -> Signal<Void, No
|
|||||||
return modify
|
return modify
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class PendingMessageRequestDependencyTag: NetworkRequestDependencyTag {
|
final class PendingMessageRequestDependencyTag: NetworkRequestDependencyTag {
|
||||||
let messageId: MessageId
|
let messageId: MessageId
|
||||||
|
|
||||||
init(messageId: MessageId) {
|
init(messageId: MessageId) {
|
||||||
@ -970,7 +970,7 @@ public final class PendingMessageManager {
|
|||||||
strongSelf.beginSendingMessages(messages.map({ $0.0.id }))
|
strongSelf.beginSendingMessages(messages.map({ $0.0.id }))
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
} else if let failureReason = reasonForError(error.errorDescription), let message = messages.first?.0 {
|
} else if let failureReason = sendMessageReasonForError(error.errorDescription), let message = messages.first?.0 {
|
||||||
for (message, _) in messages {
|
for (message, _) in messages {
|
||||||
if let context = strongSelf.messageContexts[message.id] {
|
if let context = strongSelf.messageContexts[message.id] {
|
||||||
context.error = failureReason
|
context.error = failureReason
|
||||||
@ -1292,7 +1292,7 @@ public final class PendingMessageManager {
|
|||||||
strongSelf.beginSendingMessages([messageId])
|
strongSelf.beginSendingMessages([messageId])
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if let failureReason = reasonForError(error.errorDescription) {
|
} else if let failureReason = sendMessageReasonForError(error.errorDescription) {
|
||||||
if let context = strongSelf.messageContexts[message.id] {
|
if let context = strongSelf.messageContexts[message.id] {
|
||||||
context.error = failureReason
|
context.error = failureReason
|
||||||
for f in context.statusSubscribers.copyItems() {
|
for f in context.statusSubscribers.copyItems() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user