Skip to content

Instantly share code, notes, and snippets.

@thechaudharysab
Last active October 7, 2022 06:27
Show Gist options
  • Save thechaudharysab/36b4802047b5c504033792fd75dcc9fd to your computer and use it in GitHub Desktop.
Save thechaudharysab/36b4802047b5c504033792fd75dcc9fd to your computer and use it in GitHub Desktop.
import UIKit
struct Chat {
var users: [String]
var dictionary: [String: Any] {
return ["users": users]
}
}
extension Chat {
init?(dictionary: [String:Any]) {
guard let chatUsers = dictionary["users"] as? [String] else {return nil}
self.init(users: chatUsers)
}
}
import Foundation
import MessageKit
struct ChatUser: SenderType, Equatable {
var senderId: String
var displayName: String
}
import UIKit
import InputBarAccessoryView
import Firebase
import MessageKit
import FirebaseFirestore
import SDWebImage
class ChatViewController: MessagesViewController, InputBarAccessoryViewDelegate, MessagesDataSource, MessagesLayoutDelegate, MessagesDisplayDelegate {
var currentUser: User = Auth.auth().currentUser!
var user2Name: String?
var user2ImgUrl: String?
var user2UID: String?
private var docReference: DocumentReference?
var messages: [Message] = []
override func viewDidLoad() {
super.viewDidLoad()
self.title = user2Name ?? "Chat"
navigationItem.largeTitleDisplayMode = .never
maintainPositionOnKeyboardFrameChanged = true
scrollsToLastItemOnKeyboardBeginsEditing = true
messageInputBar.inputTextView.tintColor = .systemBlue
messageInputBar.sendButton.setTitleColor(.systemTeal, for: .normal)
messageInputBar.delegate = self
messagesCollectionView.messagesDataSource = self
messagesCollectionView.messagesLayoutDelegate = self
messagesCollectionView.messagesDisplayDelegate = sel
loadChat()
}
// MARK: - Custom messages handlers
func createNewChat() {
let users = [self.currentUser.uid, self.user2UID]
let data: [String: Any] = [
"users":users
]
let db = Firestore.firestore().collection("Chats")
db.addDocument(data: data) { (error) in
if let error = error {
print("Unable to create chat! \(error)")
return
} else {
self.loadChat()
}
}
}
func loadChat() {
//Fetch all the chats which has current user in it
let db = Firestore.firestore().collection("Chats")
.whereField("users", arrayContains: Auth.auth().currentUser?.uid ?? "Not Found User 1")
db.getDocuments { (chatQuerySnap, error) in
if let error = error {
print("Error: \(error)")
return
} else {
//Count the no. of documents returned
guard let queryCount = chatQuerySnap?.documents.count else {
return
}
if queryCount == 0 {
//If documents count is zero that means there is no chat available and we need to create a new instance
self.createNewChat()
}
else if queryCount >= 1 {
//Chat(s) found for currentUser
for doc in chatQuerySnap!.documents {
let chat = Chat(dictionary: doc.data())
//Get the chat which has user2 id
if (chat?.users.contains(self.user2UID!))! {
self.docReference = doc.reference
//fetch it's thread collection
doc.reference.collection("thread")
.order(by: "created", descending: false)
.addSnapshotListener(includeMetadataChanges: true, listener: { (threadQuery, error) in
if let error = error {
print("Error: \(error)")
return
} else {
self.messages.removeAll()
for message in threadQuery!.documents {
let msg = Message(dictionary: message.data())
self.messages.append(msg!)
print("Data: \(msg?.content ?? "No message found")")
}
self.messagesCollectionView.reloadData()
self.messagesCollectionView.scrollToLastItem(at: .bottom, animated: true)
}
})
return
} //end of if
} //end of for
self.createNewChat()
} else {
print("Let's hope this error never prints!")
}
}
}
}
private func insertNewMessage(_ message: Message) {
messages.append(message)
messagesCollectionView.reloadData()
DispatchQueue.main.async {
self.messagesCollectionView.scrollToLastItem(at: .bottom, animated: true)
}
}
private func save(_ message: Message) {
let data: [String: Any] = [
"content": message.content,
"created": message.created,
"id": message.id,
"senderID": message.senderID,
"senderName": message.senderName
]
docReference?.collection("thread").addDocument(data: data, completion: { (error) in
if let error = error {
print("Error Sending message: \(error)")
return
}
self.messagesCollectionView.scrollToLastItem(at: .bottom, animated: true)
})
}
// MARK: - InputBarAccessoryViewDelegate
func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) {
let message = Message(id: UUID().uuidString, content: text, created: Timestamp(), senderID: currentUser.uid, senderName: currentUser.displayName!)
//messages.append(message)
insertNewMessage(message)
save(message)
inputBar.inputTextView.text = ""
messagesCollectionView.reloadData()
messagesCollectionView.scrollToBottom(animated: true)
}
// MARK: - MessagesDataSource
func currentSender() -> SenderType {
return Sender(id: Auth.auth().currentUser!.uid, displayName: Auth.auth().currentUser?.displayName ?? "Name not found")
}
func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType {
return messages[indexPath.section]
}
func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int {
if messages.count == 0 {
print("No messages to display")
return 0
} else {
return messages.count
}
}
// MARK: - MessagesLayoutDelegate
func avatarSize(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> CGSize {
return .zero
}
// MARK: - MessagesDisplayDelegate
func backgroundColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
return isFromCurrentSender(message: message) ? .blue: .lightGray
}
func configureAvatarView(_ avatarView: AvatarView, for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) {
if message.sender.senderId == currentUser.uid {
SDWebImageManager.shared.loadImage(with: currentUser.photoURL, options: .highPriority, progress: nil) { (image, data, error, cacheType, isFinished, imageUrl) in
avatarView.image = image
}
} else {
SDWebImageManager.shared.loadImage(with: URL(string: user2ImgUrl!), options: .highPriority, progress: nil) { (image, data, error, cacheType, isFinished, imageUrl) in
avatarView.image = image
}
}
}
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)
}
}
//
// Message.swift
// Showupia
//
// Created by Chaudhry Talha on 5/25/21.
//
import UIKit
import Firebase
import MessageKit
struct Message {
var id: String
var content: String
var created: Timestamp
var senderID: String
var senderName: String
var dictionary: [String: Any] {
return [
"id": id,
"content": content,
"created": created,
"senderID": senderID,
"senderName":senderName]
}
}
extension Message {
init?(dictionary: [String: Any]) {
guard let id = dictionary["id"] as? String,
let content = dictionary["content"] as? String,
let created = dictionary["created"] as? Timestamp,
let senderID = dictionary["senderID"] as? String,
let senderName = dictionary["senderName"] as? String
else {return nil}
self.init(id: id, content: content, created: created, senderID: senderID, senderName:senderName)
}
}
extension Message: MessageType {
var sender: SenderType {
return ChatUser(senderId: senderID, displayName: senderName)
}
var messageId: String {
return id
}
var sentDate: Date {
return created.dateValue()
}
var kind: MessageKind {
return .text(content)
}
}
@WaqasSaleem12345
Copy link

hello

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment