// // ShareViewController.swift // TimeSafariShareExtension // // Created by Aardimus on 11/24/25. // import UIKit import UniformTypeIdentifiers class ShareViewController: UIViewController { private let appGroupIdentifier = "group.app.timesafari" private let sharedPhotoBase64Key = "sharedPhotoBase64" private let sharedPhotoFileNameKey = "sharedPhotoFileName" override func viewDidLoad() { super.viewDidLoad() // Set a minimal background (transparent or loading indicator) view.backgroundColor = .systemBackground // Process image immediately without showing UI processAndOpenApp() } private func processAndOpenApp() { // extensionContext is automatically available on UIViewController when used as extension principal class guard let context = extensionContext, let inputItems = context.inputItems as? [NSExtensionItem] else { extensionContext?.completeRequest(returningItems: [], completionHandler: nil) return } processSharedImage(from: inputItems) { [weak self] success in guard let self = self, let context = self.extensionContext else { return } if success { // Set flag that shared photo is ready self.setSharedPhotoReadyFlag() // Open the main app (using minimal URL - app will detect shared data on activation) self.openMainApp() } // Complete immediately - no UI shown context.completeRequest(returningItems: [], completionHandler: nil) } } private func setSharedPhotoReadyFlag() { guard let userDefaults = UserDefaults(suiteName: appGroupIdentifier) else { return } userDefaults.set(true, forKey: "sharedPhotoReady") userDefaults.synchronize() } private func processSharedImage(from items: [NSExtensionItem], completion: @escaping (Bool) -> Void) { // Find the first image attachment for item in items { guard let attachments = item.attachments else { continue } for attachment in attachments { if attachment.hasItemConformingToTypeIdentifier(UTType.image.identifier) { attachment.loadItem(forTypeIdentifier: UTType.image.identifier, options: nil) { [weak self] (data, error) in guard let self = self else { completion(false) return } if let error = error { completion(false) return } // Handle different image data types var imageData: Data? var fileName: String = "shared-image.jpg" if let url = data as? URL { // Image provided as file URL imageData = try? Data(contentsOf: url) fileName = url.lastPathComponent } else if let image = data as? UIImage { // Image provided as UIImage imageData = image.jpegData(compressionQuality: 0.9) fileName = "shared-image.jpg" } else if let data = data as? Data { // Image provided as raw Data imageData = data fileName = "shared-image.jpg" } guard let finalImageData = imageData else { completion(false) return } // Convert to base64 let base64String = finalImageData.base64EncodedString() // Store in App Group UserDefaults guard let userDefaults = UserDefaults(suiteName: self.appGroupIdentifier) else { completion(false) return } userDefaults.set(base64String, forKey: self.sharedPhotoBase64Key) userDefaults.set(fileName, forKey: self.sharedPhotoFileNameKey) userDefaults.synchronize() completion(true) } return // Process only the first image } } } // No image found completion(false) } private func openMainApp() { // Open the main app with minimal URL - app will detect shared data on activation guard let url = URL(string: "timesafari://") else { return } var responder: UIResponder? = self while responder != nil { if let application = responder as? UIApplication { application.open(url, options: [:], completionHandler: nil) return } responder = responder?.next } // Fallback: use extension context extensionContext?.open(url, completionHandler: nil) } }