Monorepo for Aesthetic.Computer
aesthetic.computer
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}