mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
245 lines
17 KiB
Swift
245 lines
17 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import TelegramCore
|
|
import Display
|
|
import SwiftSignalKit
|
|
import TelegramUIPreferences
|
|
import AccountContext
|
|
import AccountContext
|
|
import SafariServices
|
|
import OpenInExternalAppUI
|
|
import InstantPageUI
|
|
import HashtagSearchUI
|
|
import StickerPackPreviewUI
|
|
import JoinLinkPreviewUI
|
|
import PresentationDataUtils
|
|
import UrlWhitelist
|
|
import UndoUI
|
|
|
|
func handleTextLinkActionImpl(context: AccountContext, peerId: EnginePeer.Id?, navigateDisposable: MetaDisposable, controller: ViewController, action: TextLinkItemActionType, itemLink: TextLinkItem) {
|
|
let presentImpl: (ViewController, Any?) -> Void = { controllerToPresent, _ in
|
|
controller.present(controllerToPresent, in: .window(.root))
|
|
}
|
|
|
|
let openResolvedPeerImpl: (EnginePeer?, ChatControllerInteractionNavigateToPeer) -> Void = { [weak controller] peer, navigation in
|
|
guard let peer = peer else {
|
|
return
|
|
}
|
|
context.sharedContext.openResolvedUrl(.peer(peer._asPeer(), navigation), context: context, urlContext: .generic, navigationController: (controller?.navigationController as? NavigationController), forceExternal: false, openPeer: { (peer, navigation) in
|
|
switch navigation {
|
|
case let .chat(_, subject, peekData):
|
|
if let navigationController = controller?.navigationController as? NavigationController {
|
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), subject: subject, keepStack: .always, peekData: peekData))
|
|
}
|
|
case .info:
|
|
let peerSignal: Signal<EnginePeer?, NoError>
|
|
peerSignal = context.engine.data.get(
|
|
TelegramEngine.EngineData.Item.Peer.Peer(id: peer.id)
|
|
)
|
|
navigateDisposable.set((peerSignal |> take(1) |> deliverOnMainQueue).start(next: { peer in
|
|
if let controller = controller, let peer = peer {
|
|
if let infoController = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
|
|
(controller.navigationController as? NavigationController)?.pushViewController(infoController)
|
|
}
|
|
}
|
|
}))
|
|
case let .withBotStartPayload(botStart):
|
|
if let navigationController = controller?.navigationController as? NavigationController {
|
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), botStart: botStart, keepStack: .always))
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
},
|
|
sendFile: nil,
|
|
sendSticker: nil,
|
|
sendEmoji: nil,
|
|
requestMessageActionUrlAuth: nil,
|
|
joinVoiceChat: nil,
|
|
present: presentImpl, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
|
}
|
|
|
|
let openLinkImpl: (String) -> Void = { [weak controller] url in
|
|
navigateDisposable.set((context.sharedContext.resolveUrl(context: context, peerId: peerId, url: url, skipUrlAuth: true) |> deliverOnMainQueue).start(next: { result in
|
|
if let controller = controller {
|
|
switch result {
|
|
case let .externalUrl(url):
|
|
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: url, forceExternal: false, presentationData: context.sharedContext.currentPresentationData.with({ $0 }), navigationController: controller.navigationController as? NavigationController, dismissInput: {
|
|
})
|
|
case let .peer(peer, navigation):
|
|
openResolvedPeerImpl(peer.flatMap(EnginePeer.init), navigation)
|
|
case let .botStart(peer, payload):
|
|
openResolvedPeerImpl(EnginePeer(peer), .withBotStartPayload(ChatControllerInitialBotStart(payload: payload, behavior: .interactive)))
|
|
case let .channelMessage(peer, messageId, timecode):
|
|
if let navigationController = controller.navigationController as? NavigationController {
|
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(EnginePeer(peer)), subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: timecode, setupReply: false)))
|
|
}
|
|
case let .replyThreadMessage(replyThreadMessage, messageId):
|
|
if let navigationController = controller.navigationController as? NavigationController, let effectiveMessageId = replyThreadMessage.effectiveMessageId {
|
|
let _ = ChatControllerImpl.openMessageReplies(context: context, navigationController: navigationController, present: { [weak controller] c, a in
|
|
controller?.present(c, in: .window(.root), with: a)
|
|
}, messageId: effectiveMessageId, isChannelPost: replyThreadMessage.isChannelPost, atMessage: messageId, displayModalProgress: true).start()
|
|
}
|
|
case let .replyThread(messageId):
|
|
if let navigationController = controller.navigationController as? NavigationController {
|
|
let _ = context.sharedContext.navigateToForumThread(context: context, peerId: messageId.peerId, threadId: Int64(messageId.id), messageId: nil, navigationController: navigationController, activateInput: nil, scrollToEndIfExists: false, keepStack: .always).start()
|
|
}
|
|
case let .stickerPack(name, _):
|
|
let packReference: StickerPackReference = .name(name)
|
|
controller.present(StickerPackScreen(context: context, mainStickerPack: packReference, stickerPacks: [packReference], parentNavigationController: controller.navigationController as? NavigationController), in: .window(.root))
|
|
case let .instantView(webpage, anchor):
|
|
(controller.navigationController as? NavigationController)?.pushViewController(InstantPageController(context: context, webPage: webpage, sourceLocation: InstantPageSourceLocation(userLocation: peerId.flatMap(MediaResourceUserLocation.peer) ?? .other, peerType: .group), anchor: anchor))
|
|
case let .join(link):
|
|
controller.present(JoinLinkPreviewController(context: context, link: link, navigateToPeer: { peer, peekData in
|
|
openResolvedPeerImpl(peer, .chat(textInputState: nil, subject: nil, peekData: peekData))
|
|
}, parentNavigationController: controller.navigationController as? NavigationController), in: .window(.root))
|
|
case .boost, .chatFolder:
|
|
if let navigationController = controller.navigationController as? NavigationController {
|
|
openResolvedUrlImpl(result, context: context, urlContext: peerId.flatMap { .chat(peerId: $0, message: nil, updatedPresentationData: nil) } ?? .generic, navigationController: navigationController, forceExternal: false, openPeer: { peer, navigateToPeer in
|
|
openResolvedPeerImpl(peer, navigateToPeer)
|
|
}, sendFile: nil, sendSticker: nil, sendEmoji: nil, joinVoiceChat: nil, present: { c, a in }, dismissInput: {}, contentContext: nil, progress: nil, completion: nil)
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
}))
|
|
}
|
|
|
|
let openPeerMentionImpl: (String) -> Void = { mention in
|
|
navigateDisposable.set((context.engine.peers.resolvePeerByName(name: mention, ageLimit: 10)
|
|
|> mapToSignal { result -> Signal<EnginePeer?, NoError> in
|
|
guard case let .result(result) = result else {
|
|
return .complete()
|
|
}
|
|
return .single(result)
|
|
}
|
|
|> deliverOnMainQueue).start(next: { peer in
|
|
openResolvedPeerImpl(peer, .default)
|
|
}))
|
|
}
|
|
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
switch action {
|
|
case .tap:
|
|
switch itemLink {
|
|
case .url(let url, var concealed):
|
|
let (parsedString, parsedConcealed) = parseUrl(url: url, wasConcealed: false)
|
|
if parsedConcealed {
|
|
concealed = true
|
|
}
|
|
|
|
if concealed {
|
|
var rawDisplayUrl: String = parsedString
|
|
let maxLength = 180
|
|
if rawDisplayUrl.count > maxLength {
|
|
rawDisplayUrl = String(rawDisplayUrl[..<rawDisplayUrl.index(rawDisplayUrl.startIndex, offsetBy: maxLength - 2)]) + "..."
|
|
}
|
|
var displayUrl = rawDisplayUrl
|
|
displayUrl = displayUrl.replacingOccurrences(of: "\u{202e}", with: "")
|
|
controller.present(textAlertController(context: context, title: nil, text: presentationData.strings.Generic_OpenHiddenLinkAlert(displayUrl).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_No, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Yes, action: {
|
|
openLinkImpl(url)
|
|
})]), in: .window(.root))
|
|
} else {
|
|
openLinkImpl(url)
|
|
}
|
|
case let .mention(mention):
|
|
openPeerMentionImpl(mention)
|
|
case let .hashtag(_, hashtag):
|
|
if let peerId = peerId {
|
|
let peerSignal = context.account.postbox.loadedPeerWithId(peerId)
|
|
let _ = (peerSignal
|
|
|> deliverOnMainQueue).start(next: { peer in
|
|
let searchController = HashtagSearchController(context: context, peer: EnginePeer(peer), query: hashtag)
|
|
(controller.navigationController as? NavigationController)?.pushViewController(searchController)
|
|
})
|
|
}
|
|
}
|
|
case .longTap:
|
|
switch itemLink {
|
|
case let .url(url, _):
|
|
let canOpenIn = availableOpenInOptions(context: context, item: .url(url: url)).count > 1
|
|
let openText = canOpenIn ? presentationData.strings.Conversation_FileOpenIn : presentationData.strings.Conversation_LinkDialogOpen
|
|
let actionSheet = ActionSheetController(presentationData: presentationData)
|
|
let (displayUrl, _) = parseUrl(url: url, wasConcealed: false)
|
|
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
|
ActionSheetTextItem(title: displayUrl),
|
|
ActionSheetButtonItem(title: openText, color: .accent, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
openLinkImpl(url)
|
|
}),
|
|
ActionSheetButtonItem(title: presentationData.strings.ShareMenu_CopyShareLink, color: .accent, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
UIPasteboard.general.string = url
|
|
|
|
let content: UndoOverlayContent
|
|
if url.hasPrefix("tel:") {
|
|
content = .copy(text: presentationData.strings.Conversation_PhoneCopied)
|
|
} else if url.hasPrefix("mailto:") {
|
|
content = .copy(text: presentationData.strings.Conversation_EmailCopied)
|
|
} else {
|
|
content = .linkCopied(text: presentationData.strings.Conversation_LinkCopied)
|
|
}
|
|
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
controller.present(UndoOverlayController(presentationData: presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
|
}),
|
|
ActionSheetButtonItem(title: presentationData.strings.Conversation_AddToReadingList, color: .accent, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
if let link = URL(string: url) {
|
|
let _ = try? SSReadingList.default()?.addItem(with: link, title: nil, previewText: nil)
|
|
}
|
|
})
|
|
]), ActionSheetItemGroup(items: [
|
|
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
})
|
|
])])
|
|
controller.present(actionSheet, in: .window(.root))
|
|
case let .mention(mention):
|
|
let actionSheet = ActionSheetController(presentationData: presentationData)
|
|
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
|
ActionSheetTextItem(title: mention),
|
|
ActionSheetButtonItem(title: presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
openPeerMentionImpl(mention)
|
|
}),
|
|
ActionSheetButtonItem(title: presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
UIPasteboard.general.string = mention
|
|
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
controller.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_UsernameCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
|
})
|
|
]), ActionSheetItemGroup(items: [
|
|
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
})
|
|
])])
|
|
controller.present(actionSheet, in: .window(.root))
|
|
case let .hashtag(_, hashtag):
|
|
let actionSheet = ActionSheetController(presentationData: presentationData)
|
|
actionSheet.setItemGroups([ActionSheetItemGroup(items: [
|
|
ActionSheetTextItem(title: hashtag),
|
|
ActionSheetButtonItem(title: presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
let searchController = HashtagSearchController(context: context, peer: nil, query: hashtag)
|
|
(controller.navigationController as? NavigationController)?.pushViewController(searchController)
|
|
}),
|
|
ActionSheetButtonItem(title: presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
UIPasteboard.general.string = hashtag
|
|
|
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
controller.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Conversation_HashtagCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
|
|
})
|
|
]), ActionSheetItemGroup(items: [
|
|
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
|
actionSheet?.dismissAnimated()
|
|
})
|
|
])])
|
|
controller.present(actionSheet, in: .window(.root))
|
|
}
|
|
}
|
|
}
|