Monorepo for Aesthetic.Computer aesthetic.computer
at main 163 lines 7.1 kB view raw
1// 2// MessagesViewController.swift 3// aesthetic 4// 5// Created by Rumi Tarighian on 12/5/23. 6// 7 8import UIKit 9import Messages 10import WebKit 11 12class MessagesViewController: MSMessagesAppViewController, WKScriptMessageHandler{ 13 func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { 14 if message.name == "iMessageExtension", let jsonString = message.body as? String { 15 print("Received iMessageExtension: \(jsonString)") 16 17 // Convert JSON string to Dictionary 18 if let data = jsonString.data(using: .utf8) { 19 do { 20 if let dictionary = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] { 21 // Now 'dictionary' is a Swift dictionary 22 print("JSON as dictionary: \(dictionary)") 23 24 // Handle the dictionary as needed 25 if let type = dictionary["type"] as? String, type == "tap" { 26 if let image = convertDataUrlToImage(dataUrl: dictionary["body"] as! String) { 27 displayFixedImageSticker(picture: image) 28 } else { 29 print("Image not found in the assets.") 30 } } 31 } 32 } catch { 33 print("Error parsing JSON: \(error)") 34 } 35 } 36 } 37 else if message.name == "iMessageExtensionLog" { 38 print("JavaScript Log: \(message.body)") 39 } 40 } 41 42 func convertDataUrlToImage(dataUrl: String) -> UIImage? { 43 // Check if the string is a valid data URL 44 guard dataUrl.hasPrefix("data:image/png;base64,"), 45 let base64String = dataUrl.split(separator: ",").last, 46 let imageData = Data(base64Encoded: String(base64String)) else { 47 print("Invalid data URL") 48 return nil 49 } 50 51 // Create an image from the data 52 let image = UIImage(data: imageData) 53 return image 54 } 55 var webView: WKWebView! 56 let grey: CGFloat = 32/255; 57 58 override func viewDidLoad() { 59 super.viewDidLoad() 60 let config = WKWebViewConfiguration() 61 let userScript = WKUserScript(source: "console.log = function() { window.webkit.messageHandlers.iMessageExtensionLog.postMessage([...arguments].join(' ')); }", 62 injectionTime: .atDocumentStart, 63 forMainFrameOnly: false) 64 config.userContentController.addUserScript(userScript) 65 config.userContentController.add(self, name: "iMessageExtension") 66 config.userContentController.add(self, name: "iMessageExtensionLog") 67 68 webView = WKWebView(frame: view.bounds, configuration: config) 69 webView.load(URLRequest(url: URL(string: "https://aesthetic.computer/imessage")!)) 70 webView.customUserAgent = "AestheticExtension" 71 webView.backgroundColor = UIColor(red: grey, green: grey, blue: grey, alpha: 1) 72 webView.isOpaque = false 73 74 view.addSubview(webView) 75 76 webView.backgroundColor = .black 77 } 78 79 func displayFixedImageSticker(picture: UIImage) { 80 // Ensure there is an active conversation 81 guard let conversation = activeConversation else { 82 print("Active conversation is nil") 83 return 84 } 85 86 let tempDirectory = NSTemporaryDirectory() 87 let tempFileURL = URL(fileURLWithPath: tempDirectory).appendingPathComponent("tempImage.png") 88 89 do { 90 // Write the image data to the temporary file 91 if let pngData = picture.pngData() { 92 try pngData.write(to: tempFileURL) 93 94 // Insert the attachment 95 conversation.insertAttachment(tempFileURL, withAlternateFilename: nil, completionHandler: { error in 96 if let error = error { 97 print("Error inserting attachment: \(error)") 98 } 99 }) 100 } else { 101 print("Failed to get PNG data from image") 102 } 103 } catch { 104 print("Failed to write image to temporary file: \(error)") 105 } 106 } 107 override func willBecomeActive(with conversation: MSConversation) { 108 // Called when the extension is about to move from the inactive to active state. 109 // This will happen when the extension is about to present UI. 110 111 // Use this method to configure the extension and restore previously stored state. 112 } 113 114 override func didResignActive(with conversation: MSConversation) { 115 // Called when the extension is about to move from the active to inactive state. 116 // This will happen when the user dismisses the extension, changes to a different 117 // conversation or quits Messages. 118 119 // Use this method to release shared resources, save user data, invalidate timers, 120 // and store enough state information to restore your extension to its current state 121 // in case it is terminated later. 122 } 123 124 override func didReceive(_ message: MSMessage, conversation: MSConversation) { 125 // Called when a message arrives that was generated by another instance of this 126 // extension on a remote device. 127 128 // Use this method to trigger UI updates in response to the message. 129 } 130 131 override func didStartSending(_ message: MSMessage, conversation: MSConversation) { 132 // Called when the user taps the send button. 133 } 134 135 override func didCancelSending(_ message: MSMessage, conversation: MSConversation) { 136 // Called when the user deletes the message without sending it. 137 // Use this to clean up state related to the deleted message. 138 } 139 140 override func willTransition(to presentationStyle: MSMessagesAppPresentationStyle) { 141 // Called before the extension transitions to a new presentation style. 142 143 // Use this method to prepare for the change in presentation style. 144 } 145 146 override func didTransition(to presentationStyle: MSMessagesAppPresentationStyle) { 147 super.didTransition(to: presentationStyle) 148 149 switch presentationStyle { 150 case .compact: 151 print("Extension has contracted") 152 webView.evaluateJavaScript("iMessageExtensionResize('contract')", completionHandler: nil) 153 case .expanded: 154 print("Extension has expanded") 155 webView.evaluateJavaScript("iMessageExtensionResize('expand')", completionHandler: nil) 156 case .transcript: 157 print("whatever...") 158 @unknown default: 159 fatalError("Unknown presentation style encountered") 160 } 161 } 162 163}