0

I am currently working on implementing Direct Messaging in my iOS Social Media App, and thus far I have it functioning for the most part. However, I have two issues that I haven't been able to fix:

1.) The current user (we'll call him user1) can see his own messages in the chat, but not those of the person he's messaging, and vice versa, when user2 logs in after user1 sends a message, the chat remains empty on user2's end.

2.) Each chat isn't unique, meaning that whatever message User1 sends to User2, gets shown in the convo between User1 and User3 as well rather than each chat having its own unique messages.

I am using UIKit, MessageKit, and Parse. The following code for anything regarding Messages is as follows:

//
//  ChatViewController.swift
//  VibeCheck
//
//  Created by Omar Hegazy on 4/11/23.
//

import UIKit
import MessageKit
import InputBarAccessoryView
import Parse

struct Message: MessageType
{
    var sender: SenderType
    var messageId: String
    var sentDate: Date
    var kind: MessageKind
}

class ChatViewController: MessagesViewController, MessagesDataSource, MessagesLayoutDelegate, MessagesDisplayDelegate, InputBarAccessoryViewDelegate
{
    let currentUser = PFUser.current()!
    var otherUser: PFUser!
    var messages = [MessageType]()
    var inputBar = InputBarAccessoryView()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Set up the other user
        let query = PFUser.query()
        query?.whereKey("objectId", notEqualTo: currentUser.objectId!)
        query?.findObjectsInBackground(block: { (objects, error) in
            if let users = objects as? [PFUser], let user = users.first {
                self.otherUser = user
                
                // Retrieve previous messages from Parse
                let messageQuery = PFQuery(className: "Message")
                messageQuery.whereKey("sender", equalTo: self.currentUser)
                messageQuery.whereKey("recipient", equalTo: self.otherUser!)
                let recipientQuery = PFQuery(className: "Message")
                recipientQuery.whereKey("sender", equalTo: self.otherUser!)
                recipientQuery.whereKey("recipient", equalTo: self.currentUser)
                let query = PFQuery.orQuery(withSubqueries: [messageQuery, recipientQuery])
                query.findObjectsInBackground { (objects, error) in
                    if let messages = objects {
                        for message in messages {
                            let sender = message["sender"] as! PFUser
                            let text = message["text"] as! String
                            let sentDate = message.createdAt!
                            let messageKind = MessageKind.text(text)
                            let messageSender: Sender
                            do {
                                try sender.fetchIfNeeded()
                                messageSender = Sender(senderId: sender.objectId!, displayName: sender.username ?? "")
                            } catch {
                                messageSender = Sender(senderId: sender.objectId!, displayName: "Unknown")
                                print("Error fetching sender: \(error.localizedDescription)")
                            }
                            let message = Message(sender: messageSender, messageId: message.objectId!, sentDate: sentDate, kind: messageKind)
                            self.messages.append(message)
                            print("Fetched previous messages!")
                        }

                        self.messagesCollectionView.reloadData()
                        self.messagesCollectionView.scrollToLastItem(animated: false)
                    }
                }
            }
        })

        // Configure the messages collection view and input bar
        messagesCollectionView.messagesDataSource = self
        messagesCollectionView.messagesLayoutDelegate = self
        messagesCollectionView.messagesDisplayDelegate = self
        view.addSubview(inputBar)
        inputBar.delegate = self
        inputBar.inputTextView.placeholder = "Type a message..."
        inputBar.sendButton.setTitle("Send", for: .normal)
        inputBar.sendButton.setTitleColor(view.tintColor, for: .normal)
        inputBar.sendButton.addTarget(self, action: #selector(sendButtonPressed), for: .touchUpInside)
        inputBar.translatesAutoresizingMaskIntoConstraints = false
        inputBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        inputBar.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        inputBar.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
    }
    
    func currentSender() -> SenderType
    {
        return Sender(senderId: currentUser.objectId!, displayName: currentUser.username ?? "")
    }
    
    func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int
    {
        return messages.count
    }

    func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType
    {
        return messages[indexPath.section]
    }
    
    @objc func sendButtonPressed()
    {
        let messageText = inputBar.inputTextView.text.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !messageText.isEmpty else
        {
            return
        }
        
        let message = Message(sender: currentSender(), messageId: UUID().uuidString, sentDate: Date(), kind: .text(messageText))
        messages.append(message)
        inputBar.inputTextView.text = ""
        messagesCollectionView.reloadData()
        messagesCollectionView.scrollToLastItem(animated: true)
        print("Message sent!")
        
        // Save the message to Parse
        let parseMessage = PFObject(className: "Message")
        parseMessage["sender"] = currentUser
        parseMessage["recipient"] = otherUser
        parseMessage["text"] = messageText
        parseMessage.saveInBackground()
        print("Message saved!")
    }
    
    func inputBar(_ inputBar: InputBarAccessoryView, textViewTextDidChangeTo text: String)
    {
        if text.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
        {
            inputBar.sendButton.isEnabled = false
        } else
        {
            inputBar.sendButton.isEnabled = true
        }
    }
    
    func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String)
    {
        sendButtonPressed()
    }
}

and

import UIKit
import MessageKit
import Parse

class DirectMessagingViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
{   var otherUsers = [PFUser]()
    var currentUser: PFUser!
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return otherUsers.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = otherUsers[indexPath.row].username
        cell.accessoryType = .disclosureIndicator
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        
        // Show chat messages
        let vc = ChatViewController()
        vc.title = otherUsers[indexPath.row].username
        navigationController?.pushViewController(vc, animated: true)
    }
    
    @IBOutlet var myTable: UITableView!
    
    override func viewDidLoad()
       {
           super.viewDidLoad()
           
           myTable.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
           myTable.delegate = self
           myTable.dataSource = self
           
           // Get current user
           currentUser = PFUser.current()
           
           // Query for other users
           let query = PFUser.query()
           query?.whereKey("objectId", notEqualTo: currentUser.objectId!)
           query?.findObjectsInBackground(block: { (users, error) in
               if let users = users as? [PFUser] {
                   self.otherUsers = users
                   self.myTable.reloadData()
               } else {
                   print("Error querying for users: \(error?.localizedDescription ?? "")")
               }
           })
       }
   }

DirectMessagingViewControler() is what displays the users that you can chat with as well as the messages in each chat, while ChatViewController() handles everything regarding sending and receiving messages as well as fetching them.

Edit: I realized that I accidentally uploaded DirectMessageViewController twice. I have fixed it and now you can see ChatViewController.

0 Answers0