Swiftgram/TelegramUI/OpenChatMessage.swift
2018-01-11 22:44:38 +04:00

256 lines
14 KiB
Swift

import Foundation
import Display
import AsyncDisplayKit
import Postbox
import TelegramCore
import SwiftSignalKit
import PassKit
func openChatMessage(account: Account, message: Message, reverseMessageGalleryOrder: Bool, navigationController: NavigationController?, dismissInput: @escaping () -> Void, present: @escaping (ViewController, Any?) -> Void, transitionNode: @escaping (MessageId, Media) -> ASDisplayNode?, addToTransitionSurface: @escaping (UIView) -> Void, openUrl: (String) -> Void, openPeer: @escaping (Peer, ChatControllerInteractionNavigateToPeer) -> Void, callPeer: @escaping (PeerId) -> Void, sendSticker: @escaping (TelegramMediaFile) -> Void, setupTemporaryHiddenMedia: @escaping (Signal<InstantPageGalleryEntry?, NoError>, Int, Media) -> Void) -> Bool {
var galleryMedia: Media?
var otherMedia: Media?
var instantPageMedia: [InstantPageGalleryEntry]?
for media in message.media {
if let file = media as? TelegramMediaFile {
galleryMedia = file
} else if let image = media as? TelegramMediaImage {
galleryMedia = image
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
if content.embedUrl != nil && !webEmbedVideoContentSupportsWebpage(content) {
openUrl(content.url)
return true
} else {
if let file = content.file {
galleryMedia = file
} else if let image = content.image {
galleryMedia = image
}
if let instantPage = content.instantPage, let galleryMedia = galleryMedia {
switch websiteType(of: content) {
case .instagram, .twitter:
let medias = instantPageGalleryMedia(webpageId: webpage.webpageId, page: instantPage, galleryMedia: galleryMedia)
if medias.count > 1 {
instantPageMedia = medias
}
case .generic:
break
}
}
}
} else if let mapMedia = media as? TelegramMediaMap {
galleryMedia = mapMedia
} else if let contactMedia = media as? TelegramMediaContact {
otherMedia = contactMedia
}
}
if let instantPageMedia = instantPageMedia, let galleryMedia = galleryMedia {
var centralIndex: Int = 0
for i in 0 ..< instantPageMedia.count {
if instantPageMedia[i].media.media.id == galleryMedia.id {
centralIndex = i
break
}
}
let gallery = InstantPageGalleryController(account: account, entries: instantPageMedia, centralIndex: centralIndex, replaceRootController: { [weak navigationController] controller, ready in
if let navigationController = navigationController {
navigationController.replaceTopController(controller, animated: false, ready: ready)
}
})
setupTemporaryHiddenMedia(gallery.hiddenMedia, centralIndex, galleryMedia)
dismissInput()
present(gallery, InstantPageGalleryControllerPresentationArguments(transitionArguments: { entry in
var selectedTransitionNode: ASDisplayNode?
if entry.index == centralIndex {
selectedTransitionNode = transitionNode(message.id, galleryMedia)
}
if let selectedTransitionNode = selectedTransitionNode {
return GalleryTransitionArguments(transitionNode: selectedTransitionNode, addToTransitionSurface: addToTransitionSurface)
}
return nil
}))
return true
} else if let galleryMedia = galleryMedia {
if let mapMedia = galleryMedia as? TelegramMediaMap {
dismissInput()
present(legacyLocationController(message: message, mapMedia: mapMedia, account: account, openPeer: { peer in
openPeer(peer, .info)
}, sendLiveLocation: { coordinate, period in
}, stopLiveLocation: {
account.telegramApplicationContext.liveLocationManager?.cancelLiveLocation(peerId: message.id.peerId)
}), nil)
} else if let file = galleryMedia as? TelegramMediaFile, file.isSticker {
for attribute in file.attributes {
if case let .Sticker(_, reference, _) = attribute {
if let reference = reference {
let controller = StickerPackPreviewController(account: account, stickerPack: reference)
controller.sendSticker = sendSticker
dismissInput()
present(controller, nil)
}
break
}
}
} else if let file = galleryMedia as? TelegramMediaFile, file.isMusic || file.isVoice || file.isInstantVideo {
let location: PeerMessagesPlaylistLocation
let playerType: MediaManagerPlayerType
if (file.isVoice || file.isInstantVideo) && message.tags.contains(.voiceOrInstantVideo) {
location = .messages(peerId: message.id.peerId, tagMask: .voiceOrInstantVideo, at: message.id)
playerType = .voice
} else if file.isMusic && message.tags.contains(.music) {
location = .messages(peerId: message.id.peerId, tagMask: .music, at: message.id)
playerType = .music
} else {
location = .singleMessage(message.id)
playerType = (file.isVoice || file.isInstantVideo) ? .voice : .music
}
account.telegramApplicationContext.mediaManager.setPlaylist(PeerMessagesMediaPlaylist(postbox: account.postbox, network: account.network, location: location), type: playerType)
} else if let file = galleryMedia as? TelegramMediaFile, file.mimeType == "application/vnd.apple.pkpass" || (file.fileName != nil && file.fileName!.lowercased().hasSuffix(".pkpass")) {
let _ = (account.postbox.mediaBox.resourceData(file.resource, option: .complete(waitUntilFetchStatus: true))
|> take(1)
|> deliverOnMainQueue).start(next: { data in
guard let navigationController = navigationController else {
return
}
if data.complete, let content = try? Data(contentsOf: URL(fileURLWithPath: data.path)) {
var error: NSError?
let pass = PKPass(data: content, error: &error)
if error == nil {
let controller = PKAddPassesViewController(pass: pass)
if let window = navigationController.view.window {
window.rootViewController?.present(controller, animated: true)
}
}
}
})
/*
NSData *passData = [[NSData alloc] initWithContentsOfFile:[_companion fileUrlForDocumentMedia:documentAttachment].path];
NSError *error;
PKPass *pass = [[PKPass alloc] initWithData:passData error:&error];
if (error == nil)
{
[self presentViewController:[[PKAddPassesViewController alloc] initWithPass:pass] animated:true completion:nil];
return nil;
}
*/
} else {
let gallery = GalleryController(account: account, messageId: message.id, invertItemOrder: reverseMessageGalleryOrder, replaceRootController: { [weak navigationController] controller, ready in
navigationController?.replaceTopController(controller, animated: false, ready: ready)
}, baseNavigationController: navigationController)
dismissInput()
present(gallery, GalleryControllerPresentationArguments(transitionArguments: { messageId, media in
let selectedTransitionNode = transitionNode(messageId, media)
if let selectedTransitionNode = selectedTransitionNode {
return GalleryTransitionArguments(transitionNode: selectedTransitionNode, addToTransitionSurface: addToTransitionSurface)
}
return nil
}))
}
return true
} else if let contact = otherMedia as? TelegramMediaContact {
let _ = (account.postbox.modify { modifier -> (Peer?, Bool?) in
if let peerId = contact.peerId {
return (modifier.getPeer(peerId), modifier.isPeerContact(peerId: peerId))
} else {
return (nil, nil)
}
} |> deliverOnMainQueue).start(next: { peer, isContact in
guard let peer = peer else {
return
}
let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 }
let controller = ActionSheetController(presentationTheme: presentationData.theme)
let dismissAction: () -> Void = { [weak controller] in
controller?.dismissAnimated()
}
var items: [ActionSheetItem] = []
if let peerId = contact.peerId {
items.append(ActionSheetButtonItem(title: presentationData.strings.Conversation_SendMessage, action: {
dismissAction()
openPeer(peer, .chat(textInputState: nil))
}))
if let isContact = isContact, !isContact {
items.append(ActionSheetButtonItem(title: presentationData.strings.Conversation_AddContact, action: {
dismissAction()
let _ = addContactPeerInteractively(account: account, peerId: peerId, phone: contact.phoneNumber).start()
}))
}
items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_TelegramCall, action: {
dismissAction()
callPeer(peerId)
}))
}
items.append(ActionSheetButtonItem(title: presentationData.strings.UserInfo_PhoneCall, action: {
dismissAction()
account.telegramApplicationContext.applicationBindings.openUrl("tel:\(formatPhoneNumber(contact.phoneNumber).replacingOccurrences(of: " ", with: ""))")
}))
controller.setItemGroups([
ActionSheetItemGroup(items: items),
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
])
dismissInput()
present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
})
return true
}
return false
}
func openChatInstantPage(account: Account, message: Message, navigationController: NavigationController) {
for media in message.media {
if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
if let _ = content.instantPage {
var textUrl: String?
if let pageUrl = URL(string: content.url) {
inner: for attribute in message.attributes {
if let attribute = attribute as? TextEntitiesMessageAttribute {
for entity in attribute.entities {
switch entity.type {
case let .TextUrl(url):
if let parsedUrl = URL(string: url) {
if pageUrl.scheme == parsedUrl.scheme && pageUrl.host == parsedUrl.host && pageUrl.path == parsedUrl.path {
textUrl = url
}
}
case .Url:
let nsText = message.text as NSString
var entityRange = NSRange(location: entity.range.lowerBound, length: entity.range.upperBound - entity.range.lowerBound)
if entityRange.location + entityRange.length > nsText.length {
entityRange.location = max(0, nsText.length - entityRange.length)
entityRange.length = nsText.length - entityRange.location
}
let url = nsText.substring(with: entityRange)
if let parsedUrl = URL(string: url) {
if pageUrl.scheme == parsedUrl.scheme && pageUrl.host == parsedUrl.host && pageUrl.path == parsedUrl.path {
textUrl = url
}
}
default:
break
}
}
break inner
}
}
}
var anchor: String?
if let textUrl = textUrl, let anchorRange = textUrl.range(of: "#") {
anchor = String(textUrl[anchorRange.upperBound...])
}
let pageController = InstantPageController(account: account, webPage: webpage, anchor: anchor)
navigationController.pushViewController(pageController)
}
break
}
}
}