Firebase Tutorial: Real-time Chat

private let db = Firestore.firestore()
private var reference: CollectionReference?

You can certainly use whatever database you’d like for your chat app. However I’d recommend going through the tutorial first as it was written with Firestore so you can get a firm grasp of the concepts.

How can I make the out going bubble blue and keep the in coming chat bubble white

How to make ChatViewController without using Firebase ? … Do u have any code in Swift ?

var kind: MessageData {
if let image = image {
return .photo(image)
} else {
return .text(content)
}
}

error message for above in file (Models/Message.swift) : Use of undeclared type ‘MessageData’

I’m new for swift, anyone knows how to fix it will be appreciated. That’s the only error after I update to xcode10.

You can either change the primary color defined in Extensions/UIColor+Additions.swift or change the color from primary to a blue color in backgroundColor(for:at:in:) located in ChatViewController/MessagesDisplayDelegate.

I’m not sure what you mean. This tutorial was written to use Firebase so that is all that is supported at this time.

It seems like something is wrong with the MessageKit framework. Did you install it with cocoa pods? If you did did you accidentally run pod update instead of pod install, that would cause you to be on a different version of MessageKit than the tutorial was written for.

I am running xcode 9 using swift 4 on my Mac. I tried to download the xcode project you provided me but my computer says it does not support the version you gave me and it refused to open the project. I’m afraid if I update my xcode project that I will loose my current project in which is written in swift 4 :frowning:

Also in the message kit documentation
To change to the back ground color of my chat bubble to blue . It uses the template backgroundColor (for:at:in) . My question is how do I fill out the parameters for at in . Would it be something like label.backgroundColor = UIColor(red: 0/255, green: 159/255, blue: 184/255, alpha: 1.0). Is that what I put in the code for : at : in . I ask because I am trying to understand documentation and how to implement them in my project.

thanks @naturaln0va , I will try to fix it. It seems need to download the project again and redo the proccess from the pod install. any other method could solve this?

Take a look at the tutorial, in ChatViewController.swift you return a color in that method. You aren’t setting the color to a specific view, you’re implementing a delegate method.

This tutorial is written for Xcode 10. With some modifications the project can run on Xcode 9, but that isn’t supported.

I think re-downloading would be the easiest way. You could try deleting the cocoa pods installation, but that might cause more issues.

I tried to create my own code but was not able to get bubble text to appear in my action sheet after pressing the send message. Below is my code hopefully you can point me in the right direction.

import UIKit
import MessageKit
import Firebase

class ChatViewController: MessagesViewController
{
var chat:Chat!
var currentUser:User!
var messages = Message
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

    let testMessage = User(uid: currentUser.uid, username: "", fullName: "", bio: "", website: "", follows: [], followedBy: [], profileImage: currentUser.profileImage)
    //insertNewMessage(Message.toDictionary(messages))
    

    

    messageInputBar.delegate = self
    messagesCollectionView.messagesDataSource = self
    messagesCollectionView.messagesLayoutDelegate = self
    messagesCollectionView.messagesDisplayDelegate = self
}










var messagesRef =  WADatabaseReference.messages.reference()


override func viewDidLoad() {
    super.viewDidLoad()

messagesCollectionView.messagesDataSource = self

    let backButton  = UIBarButtonItem(image:UIImage(named:"icon - back"),style:.plain, target:self, action:#selector(back))
    

    self.navigationItem.leftBarButtonItem = backButton
messagesCollectionView.messagesDataSource = self
    

    self.observeMessages()
    // Do any additional setup after loading the view.
}


@objc func back(_sender:UIBarButtonItem){
    

    self.navigationController?.popToRootViewController(animated: true)
}
override func viewDidLayoutSubviews() {
    messagesCollectionView.contentInset.bottom = messageInputBar.frame.height
    messagesCollectionView.scrollIndicatorInsets.bottom = messageInputBar.frame.height//input bar put in********
}


func iMessage() {
    defaultStyle()
    messageInputBar.isTranslucent = false
    messageInputBar.backgroundView.backgroundColor = .white
    messageInputBar.separatorLine.isHidden = true
    messageInputBar.inputTextView.backgroundColor = UIColor(red: 245/255, green: 245/255, blue: 245/255, alpha: 1)
    messageInputBar.inputTextView.placeholderTextColor = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1)
    messageInputBar.inputTextView.textContainerInset = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 36)
    messageInputBar.inputTextView.placeholderLabelInsets = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 36)
    messageInputBar.inputTextView.layer.borderColor = UIColor(red: 200/255, green: 200/255, blue: 200/255, alpha: 1).cgColor
    messageInputBar.inputTextView.layer.borderWidth = 1.0
    messageInputBar.inputTextView.layer.cornerRadius = 16.0
    messageInputBar.inputTextView.layer.masksToBounds = true
    messageInputBar.inputTextView.scrollIndicatorInsets = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
    messageInputBar.setRightStackViewWidthConstant(to: 36, animated: true)
    messageInputBar.setStackViewItems([messageInputBar.sendButton], forStack: .right, animated: true)
    messageInputBar.sendButton.imageView?.backgroundColor = UIColor(red: 69/255, green: 193/255, blue: 89/255, alpha: 1)
    messageInputBar.sendButton.contentEdgeInsets = UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
    messageInputBar.sendButton.setSize(CGSize(width: 36, height: 36), animated: true)
    messageInputBar.sendButton.image =  imageLiteral(resourceName: "ic_up")
    messageInputBar.sendButton.title = nil
    messageInputBar.sendButton.imageView?.layer.cornerRadius = 16
    messageInputBar.sendButton.backgroundColor = .clear
    messageInputBar.textViewPadding.right = -38
}//*******


func defaultStyle() {
    let newMessageInputBar = MessageInputBar()
    newMessageInputBar.sendButton.tintColor = UIColor(red: 69/255, green: 193/255, blue: 89/255, alpha: 1)
    newMessageInputBar.delegate = self as! MessageInputBarDelegate
    messageInputBar = newMessageInputBar
    reloadInputViews()
}

extension ChatViewController
{
func PressSend(_ button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: Date!)
{
if chat.messageIds.count == 0 {
chat.save()

        for account in chat.users {
            account.save(new: chat)
        }
    }
    

        

        let newMessage = Message(senderUID: currentUser.uid, senderDisplayName: currentUser.fullName, type: messagesRef.description() , text: text)
        newMessage.save()

func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) → NSAttributedString? {
let name = message.sender.displayName
return NSAttributedString(string: name, attributes: [NSAttributedStringKey.font: UIFont.preferredFont(forTextStyle: .caption1)])//1

}
func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle {
    return .bubble//2

}

extension ChatViewController: MessagesDataSource
{
func currentSender() → Sender {
return currentSender()
}

func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType {
    return messages[indexPath.section] as! MessageType
}

func numberOfMessages(in messagesCollectionView: MessagesCollectionView) -> Int {
    return messages.count
}

//

}

func isFromCurrentSender(message: MessageType) -> Bool {

return true
}

extension ChatViewController
{
func observeMessages()
{
let chatMessageIdsRef = chat.ref.child(“messageIds”)
chatMessageIdsRef.observe(.childAdded, with: { snapshot in
let messageId = snapshot.value as! String
WADatabaseReference.messages.reference().child(messageId).observe(.value, with: { snapshot in
let message = Message(dictionary: snapshot.value as! [String : Any])
self.messages.append(message)
// self.add(message)
// self.finishReceivingMessage()
})
})
}
}//

extension ChatViewController: MessageInputBarDelegate {

func messageInputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String) 

inputBar.inputTextView.text = String()
messagesCollectionView.scrollToBottom()
}
func backgroundColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) → UIColor {
return isFromCurrentSender(message: message) ? UIColor(red: 69/255, green: 193/255, blue: 89/255, alpha: 1) : UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1)
}

func messageStyle(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageStyle {
    let corner: MessageStyle.TailCorner = isFromCurrentSender(message: message) ? .bottomRight : .bottomLeft
    return .bubbleTail(corner, .curved)

}
}

func currentSender() → Sender {
return Sender(id: currentSender().id, displayName: “”)
}

// 2
func numberOfMessages(in messagesCollectionView: MessagesCollectionView) → Int {
return 1

}

// 3
func messageForItem(at indexPath: IndexPath,
in messagesCollectionView: MessagesCollectionView) → MessageType {

return Sender(id: currentSender().id, displayName: "") as! MessageType

}

// 4
func cellTopLabelAttributedText(for message: MessageType,
at indexPath: IndexPath) → NSAttributedString? {

let name = message.sender.displayName
return NSAttributedString(
    string: name,
    attributes: [
        .font: UIFont.preferredFont(forTextStyle: .caption1),
        .foregroundColor: UIColor(white: 0.3, alpha: 1)
    ]
)

}

extension ChatViewController: MessagesLayoutDelegate {

func avatarSize(for message: MessageType, at indexPath: IndexPath,
                in messagesCollectionView: MessagesCollectionView) -> CGSize {
    

    // 1
    return .zero
}


func footerViewSize(for message: MessageType, at indexPath: IndexPath,
                    in messagesCollectionView: MessagesCollectionView) -> CGSize {
    

    // 2
    return CGSize(width: 0, height: 8)
}


func heightForLocation(message: MessageType, at indexPath: IndexPath,
                       with maxWidth: CGFloat, in messagesCollectionView: MessagesCollectionView) -> CGFloat {
    

    // 3
    return 0
}

}
extension ChatViewController: MessagesDisplayDelegate {

func Color(for message: MessageType, at indexPath: IndexPath,
                     in messagesCollectionView: MessagesCollectionView) -> UIColor {
    

    // 1
    return .blue
    

}


func shouldDisplayHeader(for message: MessageType, at indexPath: IndexPath,
                         in messagesCollectionView: MessagesCollectionView) -> Bool {
    

    // 2
    return false
}


func cStyle(for message: MessageType, at indexPath: IndexPath,
                  in messagesCollectionView: MessagesCollectionView) -> MessageStyle {
    

    let corner: MessageStyle.TailCorner = isFromCurrentSender(message: message) ? .bottomRight : .bottomLeft
    

    // 3
    return .bubbleTail(corner, .curved)
}


private func insertNewMessage(_ message: Message) {
    guard !messages.contains(message) else {
        return
    }
    

    messages.append(message)
  //  messages.sort(by: message)
    

    let isLatestMessage = messages.index(of: message) == (messages.count - 1)
    //let shouldScrollToBottom = messagesCollectionView.isAtBottom && isLatestMessage
    

    messagesCollectionView.reloadData()
    

    if isLatestMessage {
        DispatchQueue.main.async {
            self.messagesCollectionView.scrollToBottom(animated: true
            )
        }
func save(_ message: Message) {
   // reference?.addDocument(data: message.representation) { error in

// if let e = {
// print(“Error sending message: (e.localizedDescription)”)
// return
// }
//
self.messagesCollectionView.scrollToBottom()
}
func reggiemessageInputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String) {

    // 1
    let message = messages

    // 2


    // 3
    inputBar.inputTextView.text = ""
}
}

}
}

I’m not sure what you’re trying to do, also your code you pasted in the comment is not formatted correctly. Can you repost and fix the formatting, or post the code to a GitHub Gist?

I am using swift 4 xcode 9 . I am using an existing project I just want to type something in the collection view press send and have that message appear on screen I don’t really care if I have an image . I just wanted to get a code that will work. When I type in my action sheet and press send the text disappears but the text i typed in disappears instead of appearing on screen.

It’s still not super clear what you’re trying to do, but the sending logic is contained in messageInputBar(_ inputBar: MessageInputBar, didPressSendButtonWith text: String).

Again I’d recommend going through the whole tutorial so you can get a better understanding on how this all works together. Then I think it will be easier to incorporate the stuff you’ve learned into your application.

Hi, Awesome tutorial.

I was wondering if anyone has figured out if it is possible to also send audio files or record voice messages?
And if it would be possible to delete messages from the chat ui

Chris

@naturaln0va Do you have any feedback about this? Thank you - much appreciated! :]