// // Copyright 2024 New Vector Ltd. // // SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial // Please see LICENSE files in the repository root for full details. // import IntentsUI import SwiftUI class ShareExtensionViewController: UIViewController { private let appSettings: CommonSettingsProtocol = AppSettings() private let hostingController = UIHostingController(rootView: ShareExtensionView()) override func viewDidLoad() { super.viewDidLoad() addChild(hostingController) view.addMatchedSubview(hostingController.view) hostingController.didMove(toParent: self) MXLog.configure(currentTarget: "shareextension", filePrefix: "shareextension", logLevel: appSettings.logLevel) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) Task { if let payload = await prepareSharePayload() { await self.openMainApp(payload: payload) } self.dismiss() } } // MARK: - Private private func prepareSharePayload() async -> ShareExtensionPayload? { guard let extensionItem = extensionContext?.inputItems.first as? NSExtensionItem, let itemProvider = extensionItem.attachments?.first else { return nil } let roomID = (extensionContext?.intent as? INSendMessageIntent)?.conversationIdentifier if let fileURL = await itemProvider.storeData() { return .mediaFile(roomID: roomID, mediaFile: .init(url: fileURL, suggestedName: fileURL.lastPathComponent)) } else if let url = await itemProvider.loadTransferable(type: URL.self) { return .text(roomID: roomID, text: url.absoluteString) } else if let string = await itemProvider.loadString() { return .text(roomID: roomID, text: string) } else { MXLog.error("Failed loading NSItemProvider data: \(itemProvider)") return nil } } private func openMainApp(payload: ShareExtensionPayload) async { guard let payload = urlEncodeSharePayload(payload) else { MXLog.error("Failed preparing share payload") return } guard let url = URL(string: "\(InfoPlistReader.main.baseBundleIdentifier):/\(ShareExtensionConstants.urlPath)?\(payload)") else { MXLog.error("Failed retrieving main application scheme") return } await openURL(url) } private func urlEncodeSharePayload(_ payload: ShareExtensionPayload) -> String? { let data: Data do { data = try JSONEncoder().encode(payload) } catch { MXLog.error("Failed encoding share payload with error: \(error)") return nil } guard let jsonString = String(data: data, encoding: .utf8) else { MXLog.error("Invalid payload data") return nil } return jsonString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) } private func dismiss() { extensionContext?.completeRequest(returningItems: [], completionHandler: nil) } private func openURL(_ url: URL) async { var responder: UIResponder? = self while responder != nil { if let application = responder as? UIApplication { await application.open(url) return } responder = responder?.next } } }