Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //
- // MessagingViewController.swift
- //
- // Created by Mario Figueroa on 6/24/16.
- // Copyright © 2016 EliteByte. All rights reserved.
- //
- import UIKit
- import TwilioIPMessagingClient
- import TwilioCommon
- import FirebaseAuth
- import FirebaseDatabase
- import SlackTextViewController
- import CoreData
- class MessagingViewController: SLKTextViewController {
- // IP Messaging client instance - will create on initialization
- var client: TwilioIPMessagingClient? = nil
- // Handle to the default general channel
- var generalChannel: TWMChannel? = nil
- // Identity that was assigned to us by the server
- var identity = ""
- // A list of all the messages displayed in the UI
- var messages: [Message] = []
- var fetchedMessages: [Message] = []
- // Reference to the Firebase DataBase
- var ref = FIRDatabaseReference.init()
- // Core Data and Firebase Variables
- var tempUser = User(username: "", email: "", timezone: "", bio: "")
- var coreDataConnection : Bool = false
- var coreDataMessages = [Message]()
- // Logistical Variables
- var authors = [String]()
- var channelName = ""
- var directMessage = false
- // Segue Variables
- var recipient = String()
- var recipientUsername = String()
- @IBOutlet weak var loadingLabel: UILabel!
- @IBOutlet weak var loadingIndicator: UIActivityIndicatorView!
- // MARK: View Lifecycle
- override func viewDidLoad() {
- super.viewDidLoad()
- self.ref = FIRDatabase.database().reference()
- self.shouldScrollToBottomAfterKeyboardShows = true
- self.tableView!.registerClass(MessagingTableViewCell.self, forCellReuseIdentifier: "MessagingTableViewCell")
- self.inverted = false
- if loadMessagesFromCoreData() {
- coreDataConnection = true
- }
- if directMessage {
- channelName = recipientUsername
- }
- // Fetch Access Token form the server and initialize IPM Client - this assumes you are running
- // the PHP starter app on your local machine, as instructed in the quick start guide
- self.identity = self.tempUser.username
- let deviceId = UIDevice.currentDevice().identifierForVendor!.UUIDString
- let urlString = "http://project-7178689301910177154.appspot.com/token.php?device=\(deviceId)&username=\(fetchForUsername())"
- // Get JSON from server
- let config = NSURLSessionConfiguration.defaultSessionConfiguration()
- let session = NSURLSession(configuration: config, delegate: nil, delegateQueue: nil)
- let url = NSURL(string: urlString)
- let request = NSMutableURLRequest(URL: url!)
- request.HTTPMethod = "GET"
- // Make HTTP request
- session.dataTaskWithRequest(request, completionHandler: { data, response, error in
- if (data != nil) {
- // Parse result JSON
- let json = JSON(data: data!)
- let token = json["token"].stringValue
- // Set up Twilio IPM client
- let accessManager = TwilioAccessManager.init(token: token, delegate: nil)
- self.client = TwilioIPMessagingClient.ipMessagingClientWithAccessManager(accessManager, properties: nil, delegate: self)
- // Update UI on main thread
- dispatch_async(dispatch_get_main_queue()) {
- self.navigationItem.prompt = "@" + self.identity
- self.navigationItem.title = self.channelName
- }
- } else {
- print("Error fetching token :\(error)")
- }
- }).resume()
- // Set up UI controls
- self.tableView!.rowHeight = UITableViewAutomaticDimension
- self.tableView!.estimatedRowHeight = 64.0
- self.tableView!.separatorStyle = .None
- }
- override func viewDidAppear(animated: Bool) {
- synchronizeMessages()
- self.scrollToBottomMessage()
- }
- // MARK: Setup IP Messaging Channel
- func joinChannel() {
- self.generalChannel?.joinWithCompletion() {
- (result) -> Void in
- if result.isSuccessful(){
- //self.channel?.delegate = self
- //self.loadMessages()
- }
- }
- }
- func joinChannelAndSetUniqueName(name: String) {
- self.generalChannel?.joinWithCompletion() { result in
- if result.isSuccessful() {
- self.generalChannel?.setUniqueName(name) { result in
- //self.channel?.delegate = self
- //self.loadMessages()
- }
- }
- }
- }
- func loadMessages() {
- let appDel : AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
- let context : NSManagedObjectContext = appDel.managedObjectContext
- print("General Channel Count ",self.generalChannel?.messages.allObjects().count, "Current Fetched count ", self.fetchedMessages.count)
- let msgs = self.generalChannel?.messages.allObjects()
- print("All fetched Messages", msgs)
- if self.fetchedMessages.count <= msgs!.count {
- var newMessages = [Message]()
- for msg in msgs! {
- let newMsg = NSEntityDescription.insertNewObjectForEntityForName("Message", inManagedObjectContext: context) as! Message
- newMsg.author = msg.author
- newMsg.message = msg.body
- newMsg.timestamp = msg.timestamp
- newMessages.append(newMsg)
- }
- self.fetchedMessages = newMessages
- } else {abort()}
- }
- func addFetchedMessages(messages: [Message]) {
- self.fetchedMessages.appendContentsOf(messages)
- self.fetchedMessages.sortInPlace { $1.timestamp > $0.timestamp }
- }
- func addMessages(messages: [Message]) {
- self.messages.appendContentsOf(messages)
- self.messages.sortInPlace { $1.timestamp > $0.timestamp }
- self.tableView?.reloadData()
- dispatch_async(dispatch_get_main_queue()) {
- () -> Void in
- self.tableView!.reloadData()
- if self.messages.count > 0 {
- self.scrollToBottomMessage()
- }
- }
- }
- func addMessage(message: Message) {
- self.messages.append(message)
- self.messages.sortInPlace { $1.timestamp > $0.timestamp }
- self.tableView?.reloadData()
- dispatch_async(dispatch_get_main_queue()) {
- () -> Void in
- self.tableView!.reloadData()
- if self.messages.count > 0 {
- self.scrollToBottomMessage()
- }
- }
- }
- override func didPressRightButton(sender: AnyObject!) {
- self.textView.refreshFirstResponder()
- print("Button Clicked")
- if self.generalChannel?.messages != nil {
- let preMsg = textView.text!
- self.textView.text = ""
- let msg = self.generalChannel?.messages.createMessageWithBody(preMsg)
- self.generalChannel?.messages.sendMessage(msg) { result in
- print("Message Sent", msg)
- self.textView.text = ""
- self.textView.resignFirstResponder()
- }
- }
- }
- //MARK: Synch Functions
- func synchronizeMessages() {
- if coreDataMessages.count < fetchedMessages.count {
- let difference = fetchedMessages.count - coreDataMessages.count
- let unsyncedEntries = fetchedMessages.suffix(difference)
- var newEntries = [Message]()
- newEntries.appendContentsOf(unsyncedEntries)
- addMessagesToCoreData(newEntries)
- }
- if messages.count < fetchedMessages.count {
- authors = synchronizeAuthors()
- let difference = fetchedMessages.count - messages.count
- let unsyncedEntries = fetchedMessages.suffix(difference)
- var newEntries = [Message]()
- newEntries.appendContentsOf(unsyncedEntries)
- addMessages(newEntries)
- }
- }
- func synchronizeAuthors() -> [String] {
- var authors = [String]()
- if messages.count > 0 {
- for msg in messages {
- authors.append(msg.author!)
- }
- }
- return authors
- }
- //MARK: CoreData Functions
- func fetchForUsername() -> String {
- let appDel : AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
- let context : NSManagedObjectContext = appDel.managedObjectContext
- do {
- let request = NSFetchRequest(entityName: "Users")
- let results = try context.executeFetchRequest(request)
- if results.count > 0 {
- for e in results as! [NSManagedObject] {
- let username = e.valueForKey("username")
- identity = username as! String
- print("Identity", identity)
- return username as! String
- }
- }
- } catch let error as NSError {
- // Failure
- print("Fetch for username failed: \(error.localizedDescription)")
- }
- return ""
- }
- func loadMessagesFromCoreData() -> Bool {
- print("Before were found in loadMessagesFromCoreData OG, DEBUG STATUS: CoreDataMessage:", coreDataMessages.count, "Messages:", messages.count, "FetchedMessages:", fetchedMessages.count)
- messages.removeAll()
- coreDataMessages.removeAll()
- let appDel : AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
- let context : NSManagedObjectContext = appDel.managedObjectContext
- let searchFF = NSPredicate(format: "username == %@", (channelName))
- do {
- let request = NSFetchRequest(entityName: "Friend")
- request.predicate = searchFF
- let results = try context.executeFetchRequest(request) as! [Friend]
- if results.count > 0 {
- for friend in results {
- let msgs = friend.fetchMessages()
- coreDataMessages = msgs
- addMessages(msgs)
- print("Core Data Messages were succesfully fetched and written!", msgs)
- print("Results were found in loadMessagesFromCoreData OG, DEBUG STATUS: CoreDataMessage:", coreDataMessages.count, "Messages:", messages.count, "FetchedMessages:", fetchedMessages.count)
- return true
- }
- }
- print("We attempted to load messages from CoreData, but none were found.")
- return false
- } catch let error as NSError {
- print("Fetch for Friends failed: \(error.localizedDescription)")
- }
- return false
- }
- func addMessagesToCoreData(msgs : [Message]) -> Bool {
- print("We are adding these messages to core data,", msgs)
- let appDel : AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
- let context : NSManagedObjectContext = appDel.managedObjectContext
- let searchFF = NSPredicate(format: "username == %@", channelName)
- do {
- let request = NSFetchRequest(entityName: "Friend")
- request.predicate = searchFF
- let results = try context.executeFetchRequest(request) as! [Friend]
- if results.count > 0 {
- for friend in results {
- friend.addMessages(msgs)
- coreDataMessages.appendContentsOf(msgs)
- print("DEBUG STATUS: CoreDataMessage:", coreDataMessages.count, "Messages:", messages.count, "FetchedMessages:", fetchedMessages.count)
- print("NSFetch request for a former Friend was a SUCCESS, setting msgs and returning.")
- return true
- }
- print("No results for the NSFetch O.G. in addMessagesToCoreData")
- try context.save()
- }
- } catch let error as NSError {
- print("Fetch for Friends failed: \(error.localizedDescription)")
- }
- let recipientEnt = NSEntityDescription.entityForName("Friend", inManagedObjectContext: context)
- let newFriend = Friend(entity: recipientEnt!, insertIntoManagedObjectContext: context)
- // if messages.count > 0 {
- // newFriend.lastMessage = messages[messages.endIndex].message }
- newFriend.username = channelName
- newFriend.addMessages(msgs)
- coreDataMessages.appendContentsOf(msgs)
- newFriend.uuid = "channel"
- print("We have setup a new Friend with username,", channelName)
- for msg in msgs {
- let msgEnt = NSEntityDescription.entityForName("Message", inManagedObjectContext: context)
- let newMessage = Message(entity: msgEnt!, insertIntoManagedObjectContext: context)
- newMessage.author = msg.author
- newMessage.message = msg.message
- newMessage.timestamp = msg.timestamp
- newMessage.recipient = newFriend.username
- print("Setting up a new message author", msg.author)
- print("2nd OG DEBUG STATUS: CoreDataMessage:", coreDataMessages.count, "Messages:", messages.count, "FetchedMessages:", fetchedMessages.count)
- }
- do {
- try context.save()
- print("2nd OG DEBUG STATUS: CoreDataMessage:", coreDataMessages.count, "Messages:", messages.count, "FetchedMessages:", fetchedMessages.count)
- } catch{
- print("Attempt to save message in CoreData failed")
- }
- return false
- }
- // MARK: UI Logic
- // Scroll to bottom of table view for messages
- func scrollToBottomMessage() {
- if self.messages.count == 0 {
- return
- }
- let bottomMessageIndex = NSIndexPath(forRow: self.tableView!.numberOfRowsInSection(0) - 1,
- inSection: 0)
- self.tableView!.scrollToRowAtIndexPath(bottomMessageIndex, atScrollPosition: .Bottom,
- animated: true)
- }
- // MARK: UITableView Delegate
- // Return number of rows in the table
- override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- print(self.messages.count, "MESSAGES COUNT")
- return self.messages.count
- }
- // Create table view rows
- override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
- let cell = tableView.dequeueReusableCellWithIdentifier("MessagingTableViewCell", forIndexPath: indexPath) as! MessagingTableViewCell
- let message = self.messages[indexPath.row]
- cell.nameLabel.text = message.author!
- cell.nameLabel.textColor = UIColor.darkGrayColor()
- cell.bodyLabel.text = message.message
- cell.bodyLabel.textColor = UIColor.blackColor()
- let timestamp = message.timestamp!.substringWithRange(Range<String.Index>(start: message.timestamp!.startIndex.advancedBy(11), end: message.timestamp!.endIndex.advancedBy(-1)))
- cell.timestampLabel.text = timestampGenerator(timestamp)
- let index = message.author!.startIndex
- let author = message.author! as String
- if author == "elitebyte" { cell.nameLabel.textColor = UIColor.orangeColor()}
- cell.profileView.text = String(author.capitalizedString[index])
- cell.profileView.textColor = UIColor.whiteColor()
- cell.profileView.backgroundColor = pickColor(author.capitalizedString[index])
- cell.selectionStyle = .None
- return cell
- }
- func pickColor(alphabet: Character) -> UIColor {
- let alphabetColors = [0x5A8770, 0xB2B7BB, 0x6FA9AB, 0xF5AF29, 0x0088B9, 0xF18636, 0xD93A37, 0xA6B12E, 0x5C9BBC, 0xF5888D, 0x9A89B5, 0x407887, 0x9A89B5, 0x5A8770, 0xD33F33, 0xA2B01F, 0xF0B126, 0x0087BF, 0xF18636, 0x0087BF, 0xB2B7BB, 0x72ACAE, 0x9C8AB4, 0x5A8770, 0xEEB424, 0x407887]
- let str = String(alphabet).unicodeScalars
- let unicode = Int(str[str.startIndex].value)
- if 65...90 ~= unicode {
- let hex = alphabetColors[unicode - 65]
- return UIColor(red: CGFloat(Double((hex >> 16) & 0xFF)) / 255.0, green: CGFloat(Double((hex >> 8) & 0xFF)) / 255.0, blue: CGFloat(Double((hex >> 0) & 0xFF)) / 255.0, alpha: 1.0)
- }
- return UIColor.blackColor()
- }
- func timestampGenerator(timestamp : String) -> String {
- let timestampHour = timestamp.substringWithRange(Range<String.Index>(start: timestamp.startIndex.advancedBy(0), end: timestamp.endIndex.advancedBy(-10)))
- let timestampMin = timestamp.substringWithRange(Range<String.Index>(start: timestamp.startIndex.advancedBy(3), end: timestamp.endIndex.advancedBy(-7)))
- let date = NSDate()
- let calendar = NSCalendar.currentCalendar()
- let components = calendar.components([ .Hour, .Minute, .Second], fromDate: date)
- let hour = components.hour
- //let minutes = components.minute
- let hourDifference = Int(timestampHour)! - hour
- let finalHour = Int(timestampHour)! - (hourDifference)
- var suffix = ""
- if (Int(timestampHour)! - 12) < 0 {
- suffix = "AM"
- } else { suffix = "PM" }
- return String(finalHour) + ":" + timestampMin + suffix
- }
- // MARK: UITableViewDataSource Delegate
- override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
- return 1
- }
- func grabUIDInfo(uid : String) -> User {
- ref.child("users").child(uid).observeSingleEventOfType(.Value, withBlock: { (snapshot) in
- if self.snapCheck(snapshot) {
- let user = User(username: snapshot.value!["username"] as! String, email: snapshot.value!["email"] as! String, timezone: snapshot.value!["timezone"] as! String, bio: snapshot.value!["bio"] as! String)
- self.tempUser = user
- }
- }) { (error) in
- }
- return tempUser
- }
- func snapCheck(snap : FIRDataSnapshot) -> Bool {
- if snap.value is NSNull {
- return false
- } else {
- return true
- }
- }
- }
- func convertMessage(msg : TWMMessage) -> Message {
- let appDel : AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
- let context : NSManagedObjectContext = appDel.managedObjectContext
- let newMsg = NSEntityDescription.insertNewObjectForEntityForName("Message", inManagedObjectContext: context) as! Message
- newMsg.author = msg.author
- newMsg.message = msg.body
- newMsg.timestamp = msg.timestamp
- return newMsg
- }
- // MARK: Twilio IP Messaging Delegate
- extension MessagingViewController: TwilioIPMessagingClientDelegate {
- // Called whenever a channel we've joined receives a new message
- func ipMessagingClient(client: TwilioIPMessagingClient!, channel: TWMChannel!,
- messageAdded message: TWMMessage!) {
- self.loadMessages()
- self.addFetchedMessages([convertMessage(message)])
- self.addMessage(convertMessage(message))
- self.addMessagesToCoreData([convertMessage(message)])
- self.synchronizeMessages()
- self.authors = self.synchronizeAuthors()
- print("Message Recieved OG DEBUG STATUS: CoreDataMessage:", coreDataMessages.count, "Messages:", messages.count, "FetchedMessages:", fetchedMessages.count)
- }
- func joinChannelWithUniqueID(uniqueID : String, channelType : TWMChannelType) -> Bool {
- self.generalChannel = client?.channelsList().channelWithUniqueName(uniqueID)
- if let generalChannel = self.generalChannel {
- generalChannel.joinWithCompletion({ result in
- if result.isSuccessful() {
- self.loadMessages()
- self.synchronizeMessages()
- self.authors = self.synchronizeAuthors()
- print("We have joine a ", channelType, "chat channel", uniqueID)
- }
- })
- return true
- }
- return false
- }
- func createChannelWithUniqueID(uniqueID : String, friendlyName : String, channelType : TWMChannelType, recipient : String?) -> Bool {
- var returnVal = false
- client!.channelsList().createChannelWithOptions([TWMChannelOptionFriendlyName: friendlyName, TWMChannelOptionType: channelType.rawValue], completion: { (result, channel) -> Void in
- if result.isSuccessful() {
- self.generalChannel = channel
- self.generalChannel?.joinWithCompletion({ result in
- self.generalChannel?.setUniqueName(uniqueID, completion: { result in
- print("We have created a", channelType, "chat channel ", uniqueID)
- if channelType == TWMChannelType.Private {
- self.generalChannel?.members.inviteByIdentity(recipient) { result in
- if result.isSuccessful() {
- print(recipient, "User invited.")
- } else {
- print(recipient, "User NOT invited.")
- }
- }
- }
- self.loadMessages()
- returnVal = true
- })
- })
- }
- })
- return returnVal
- }
- func ipMessagingClient(client: TwilioIPMessagingClient!, synchronizationStatusChanged status: TWMClientSynchronizationStatus) {
- if status == .Completed && channelName != "" {
- // Join (or create) the general channel
- //clearChannelsExempt("CH7b852826051a4991a5c81ca893bcaa81")
- if directMessage {
- if joinChannelWithUniqueID(recipient + "-" + (FIRAuth.auth()?.currentUser?.uid)! , channelType: TWMChannelType.Private) {
- } else if joinChannelWithUniqueID((FIRAuth.auth()?.currentUser?.uid)! + "-" + recipient, channelType: TWMChannelType.Private){
- } else {
- createChannelWithUniqueID((FIRAuth.auth()?.currentUser?.uid)! + "-" + recipient, friendlyName: "PC:" + recipient + "-" + (FIRAuth.auth()?.currentUser?.uid)!, channelType: TWMChannelType.Private, recipient: recipientUsername)
- }
- } else {
- if joinChannelWithUniqueID(channelName, channelType: TWMChannelType.Public) {
- } else {
- createChannelWithUniqueID(channelName, friendlyName: channelName + " Chat Channel", channelType: TWMChannelType.Public, recipient: "EasterEggFromMSG.VC")
- }
- }
- }
- }
- func clearChannelsExempt(whitelistedChannel : String) {
- var deletedChannels = [String]()
- for index in (client?.channelsList().allObjects())! {
- if index.sid != whitelistedChannel {
- index.destroyWithCompletion(nil)
- deletedChannels.append(index.uniqueName)
- }
- }
- print("Cleared Channels: ", deletedChannels)
- }
- func ipMessagingClient(client: TwilioIPMessagingClient!, channelHistoryLoaded channel: TWMChannel!) {
- self.loadMessages()
- self.synchronizeMessages()
- print("History loaded OG DEBUG STATUS: CoreDataMessage:", coreDataMessages.count, "Messages:", messages.count, "FetchedMessages:", fetchedMessages.count)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement