MessageSplitViewController.swift 9.63 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
22
23
24
    //
    // MARK: - View lifecycle
    //
    
    override func viewWillAppear()
    {
        createConstraints()
25
26
        
        addNotificationHandlers()
27
28
29
    }
    
    
30
    override func viewWillDisappear()
31
    {
32
        removeNotificationHandlers()
33
34
35
    }
    
    //
36
    // MARK: - Notification handlers
37
38
    //
    
39
    func addNotificationHandlers()
40
    {
Aral Balkan's avatar
Aral Balkan committed
41
42
43
        //
        // MARK: - .SendMessage
        //
44
        sendMessageNotificationHandler = handle(MessageNotification.named(.SendMessage))
45
        {
46
            /* as */ notification in
47
            
48
            if let userInfo = (notification.userInfo as Dictionary!), messageAttributedString = userInfo["message"] as? NSAttributedString
49
            {
50
51
52
53
54
55
                println("Send message: received text: \(messageAttributedString)")
                
                //
                // Get the folder to save the message to based on the current timeline
                //
                
56
                if CurrentTimeline.path == nil
57
58
59
60
                {
                    fatalError("Conversation messages not implemented yet. Panicing!")
                }
                
61
                println("Current timeline path = \(CurrentTimeline.path)")
62
63
64
65
                
                //
                // Get the correct web prefix
                //
66
                if CurrentTimeline.relativeWebPrefix == nil
67
                {
68
                    fatalError("Could not get relative web prefix for current timeline — not implemented. Only Private, All Friends, and Public timelines implemented at the moment.")
69
70
                }
                
71
                println("Current timeline relative web prefix: \(CurrentTimeline.relativeWebPrefix)")
72
73
74
75
76
77
                
                //
                // 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)
                
78
79
80
                // 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
81

82
83
                CurrentTimeline.messageClock++
                let messageFileName = String(format:"%09d-\(ISO8601DateString())", CurrentTimeline.messageClock)
84
85
                
                // This is the URL that will be prefixed to all assets in the HTML (images, etc.)
86
                let assetURLPrefix = CurrentTimeline.relativeWebPrefix!.stringByAppendingPathComponent(messageFileName)
87
                
88
89
                println("Asset URL Prefix: \(assetURLPrefix)")
                
90
91
                println("Message file name: \(messageFileName)")
                
92
                let filePath = NSHomeDirectory().stringByAppendingPathComponent("Pulse/Sync").stringByAppendingPathComponent(CurrentTimeline.path!).stringByAppendingPathComponent(messageFileName)
93
94
95
96
                
                println("About to save message at path: \(filePath)")
                
                let fileURL:NSURL? = NSURL(fileURLWithPath: filePath, isDirectory: true)
97
                
98
                if let messageDirectoryWrapper = messageDirectoryWrapper, fileURL = fileURL
99
                {
100
101
102
                    let messageFileWrappers:[NSObject:AnyObject] = messageDirectoryWrapper.fileWrappers
                    
                    for (fileName, fileWrapper) in messageFileWrappers
103
                    {
104
105
                        println(" * \(fileName): \(fileWrapper)")
                        if fileName == "index.html"
106
                        {
107
108
                            let indexData:NSData? = fileWrapper.regularFileContents
                            if let indexData = indexData
109
                            {
110
111
                                let indexHTML = NSString(data: indexData, encoding: NSUTF8StringEncoding)
                                if var indexHTML = indexHTML
112
                                {
Aral Balkan's avatar
Aral Balkan committed
113
114
                                    // TODO: Parse markdown (?)
                                    
115
116
117
118
                                    //
                                    // Massage the HTML.
                                    //
                                    
119
120
                                    println(indexHTML)
                                    
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
                                    // Fix image URLs
                                    indexHTML = indexHTML.stringByReplacingOccurrencesOfString("file:///", withString: assetURLPrefix.stringByAppendingString("/"))
                                    
                                    // Remove redundant empty lines.
                                    indexHTML = indexHTML.stringByReplacingOccurrencesOfString("<p><br></p>", withString: "")
                                    
                                    //
                                    // 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)
                                    
                                    //
149
                                    // Create the message object and broadcast it.
150
151
                                    //
                                    let message = Message(id: messageFileName, assetURLPrefix: assetURLPrefix, folderURL: fileURL, html: indexHTML as String, synced: false)
152
                            
153
154
155
                                    //
                                    // Notify that we need to have the message displayed in the respective timeline
                                    //
156
                                    post(MessageNotification.named(.ShowMessage), from: self, with: ["message": message])
157
                                    
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
                                    //
                                    // 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!])
                                    {
                                        /* and handle callback with */ result in
                                        
                                        println("<<<<< POST MESSAGE CALLBACK!!!! >>>>>")
                                        println(result)
                                    }
                                    
175
                                    break
176
177
178
179
180
181
182
183
                                }
                            }
                        }
                    }
                }
            }
        }
    }
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
    
    
    func removeNotificationHandlers()
    {
        sendMessageNotificationHandler?.remove()
    }
    
    
    //
    // MARK: - Layout
    //
    
    func createConstraints()
    {
        view.removeConstraints(view.constraints)
        
        layout(view)
        {
            /* as */ view in
            
            view.width == view.superview!.width
            view.height == view.superview!.height
        }
    }
    
209
}