MessageSplitViewController.swift 10.8 KB
Newer Older
1
////////////////////////////////////////////////////////////////////////////////
2
3
4
5
6
7
8
//
//  MessageSplitViewController.swift
//  MessageTextEntrySpike
//
//  Created by Aral Balkan on 03/01/2015.
//  Copyright (c) 2015 ind.ie. All rights reserved.
//
9
////////////////////////////////////////////////////////////////////////////////
10
11

import Cocoa
12

13
14
class MessageSplitViewController: NSSplitViewController
{
15

16
    var sendMessageNotificationHandler:NotificationHandler?
17
    
18
19
20
21
    //
    // MARK: - View lifecycle
    //
    
22
    override func viewDidAppear()
23
    {
24
25
        super.viewDidAppear()
        
26
        createConstraints()
27
28
        
        addNotificationHandlers()
29
30
    }
    
31
    override func viewDidDisappear()
32
    {
33
34
        super.viewDidDisappear()
        
35
        removeNotificationHandlers()
36
37
38
    }
    
    //
39
    // MARK: - Notification handlers
40
41
    //
    
42
    func addNotificationHandlers()
43
    {
44
        // println("\(self): adding notification handlers.")
45
        
Aral Balkan's avatar
Aral Balkan committed
46
47
48
        //
        // MARK: - .SendMessage
        //
49
        sendMessageNotificationHandler = sendMessageNotificationHandler ?? handle(MessageNotification.named(.SendMessage))
50
        {
51
            /* as */ notification in
52
            
53
            if let userInfo = (notification.userInfo as Dictionary!), messageAttributedString = userInfo["message"] as? NSAttributedString
54
            {
55
56
57
58
59
60
                println("Send message: received text: \(messageAttributedString)")
                
                //
                // Get the folder to save the message to based on the current timeline
                //
                
61
                if CurrentTimeline.path == nil
62
63
64
65
                {
                    fatalError("Conversation messages not implemented yet. Panicing!")
                }
                
66
                println("Current timeline path = \(CurrentTimeline.path)")
67
68
69
70
                
                //
                // Get the correct web prefix
                //
71
                if CurrentTimeline.relativeWebPrefix == nil
72
                {
73
                    fatalError("Could not get relative web prefix for current timeline — not implemented. Only Private, All Friends, and Public timelines implemented at the moment.")
74
75
                }
                
76
                println("Current timeline relative web prefix: \(CurrentTimeline.relativeWebPrefix)")
77
78
79
80
81
82
                
                //
                // Create a file wrapper to save the contents as a directory.
                //
                let messageDirectoryWrapper:NSFileWrapper? = messageAttributedString.fileWrapperFromRange(NSMakeRange(0, messageAttributedString.length), documentAttributes: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: NSUTF8StringEncoding, NSExcludedElementsDocumentAttribute: ["xml", "html", "head", "body", "font", "span"], NSPrefixSpacesDocumentAttribute: 4], error: nil)
                
83
84
85
                // The file name of the message folder (this is the unique ID — unique per message folder):
                // Local message clock (padding to 9 digits — which should be large enough for any timeline as it would take 
                // about a thousand years to fill it up at ten seconds a message, every ten seconds, eight hours a day, continuously) + current timestamp in ISO 8601 format
86

87
88
                CurrentTimeline.messageClock++
                let messageFileName = String(format:"%09d-\(ISO8601DateString())", CurrentTimeline.messageClock)
89
90
                
                // This is the URL that will be prefixed to all assets in the HTML (images, etc.)
91
                let assetURLPrefix = CurrentTimeline.relativeWebPrefix!.stringByAppendingPathComponent(messageFileName)
92
                
93
94
                println("Asset URL Prefix: \(assetURLPrefix)")
                
95
96
                println("Message file name: \(messageFileName)")
                
97
                let filePath = NSHomeDirectory().stringByAppendingPathComponent("Pulse/Sync").stringByAppendingPathComponent(CurrentTimeline.path!).stringByAppendingPathComponent(messageFileName)
98
99
100
101
                
                println("About to save message at path: \(filePath)")
                
                let fileURL:NSURL? = NSURL(fileURLWithPath: filePath, isDirectory: true)
102
                
103
                if let messageDirectoryWrapper = messageDirectoryWrapper, fileURL = fileURL
104
                {
105
106
107
                    let messageFileWrappers:[NSObject:AnyObject] = messageDirectoryWrapper.fileWrappers
                    
                    for (fileName, fileWrapper) in messageFileWrappers
108
                    {
109
110
                        println(" * \(fileName): \(fileWrapper)")
                        if fileName == "index.html"
111
                        {
112
113
                            let indexData:NSData? = fileWrapper.regularFileContents
                            if let indexData = indexData
114
                            {
115
116
                                let indexHTML = NSString(data: indexData, encoding: NSUTF8StringEncoding)
                                if var indexHTML = indexHTML
117
                                {
Aral Balkan's avatar
Aral Balkan committed
118
119
                                    // TODO: Parse markdown (?)
                                    
120
121
122
123
                                    //
                                    // Massage the HTML.
                                    //
                                    
124
125
                                    println(indexHTML)
                                    
126
127
128
129
130
131
                                    // Fix image URLs
                                    indexHTML = indexHTML.stringByReplacingOccurrencesOfString("file:///", withString: assetURLPrefix.stringByAppendingString("/"))
                                    
                                    // Remove redundant empty lines.
                                    indexHTML = indexHTML.stringByReplacingOccurrencesOfString("<p><br></p>", withString: "")
                                    
132
133
134
135
136
137
138
139
140
141
142
143
144
145
                                    //
                                    // If this is a new person notification, add the correct class wrapper for styling.
                                    //
                                    if let messageType = userInfo["type"] as? String
                                    {
                                        println("Got a valid userinfo type")
                                        if messageType == MessageType.named(.NewPersonNotification)
                                        {
                                            println("Got a new user notification")
                                            indexHTML = NSString(format: "<div class=\"new-person-notification\">%@</div>", indexHTML)
                                        }
                                    }

                                    
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
                                    //
                                    // Update the index.html.
                                    //
                                    
                                    // Remove the index.html file wrapper.
                                    messageDirectoryWrapper.removeFileWrapper(fileWrapper as! NSFileWrapper)
                                    
                                    // And replace it with the new index.html we created.
                                    let newIndexHTMLData:NSData? = indexHTML.dataUsingEncoding(NSUTF8StringEncoding)
                                    
                                    if let newIndexHTMLData = newIndexHTMLData
                                    {
                                        let newIndexHTMLFileWrapper = NSFileWrapper(regularFileWithContents: newIndexHTMLData)
                                        newIndexHTMLFileWrapper.preferredFilename = "index.html"
                                        messageDirectoryWrapper.addFileWrapper(newIndexHTMLFileWrapper)
                                    }
                                    
                                    // TODO: Error checking.
                                    messageDirectoryWrapper.writeToURL(fileURL, options: NSFileWrapperWritingOptions.Atomic, originalContentsURL: nil, error: nil)
                                    println(messageDirectoryWrapper)
                                    
                                    //
168
                                    // Create the message object and broadcast it.
169
170
                                    //
                                    let message = Message(id: messageFileName, assetURLPrefix: assetURLPrefix, folderURL: fileURL, html: indexHTML as String, synced: false)
171
                            
172
173
174
175
176
177
178
179
180
181
                                    //
                                    // Inform Node that it should post the message to the timeline
                                    // (TODO: Research: should we base this on the Pulse event flow instead? Which is cleaner?)
                                    //
                                    // Note: In the arguments, below:
                                    // * message file name is the message ID
                                    // * message body is the indexHTML
                                    // *
                                    //
                                    Node.sharedInstance.call(remoteFunction.named(.postMessage), withArguments: [messageFileName, indexHTML, CurrentTimeline.id!])
182
183
184
185
186
                                    {
                                        /* and handle callback with */ result in
                                        
                                        // println("<<<<< POST MESSAGE CALLBACK!!!! >>>>>")
                                        println(result)
187
                                    }
188
189
190
191
192
193
194

                                    
                                    //
                                    // Notify that we need to have the message displayed in the respective timeline
                                    //
                                    post(MessageNotification.named(.ShowMessage), from: self, with: ["message": message])
                                    
195
                                    
196
                                    break
197
198
199
200
201
202
203
204
                                }
                            }
                        }
                    }
                }
            }
        }
    }
205
206
207
208
    
    
    func removeNotificationHandlers()
    {
209
        // println("\(self): removing notification handlers")
210
        
211
        sendMessageNotificationHandler?.remove()
212
        sendMessageNotificationHandler = nil
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
    }
    
    
    //
    // MARK: - Layout
    //
    
    func createConstraints()
    {
        view.removeConstraints(view.constraints)
        
        layout(view)
        {
            /* as */ view in
            
            view.width == view.superview!.width
            view.height == view.superview!.height
        }
    }
    
233
}