0

I am implementing a Chat between driver and user in a cab app. I am getting the message from API and displaying it in chat but the chat flips depending on the ID of the last msg

when latest message sender is 'pu'

when latest message sender is 'up'

I just want to add the incoming msg on the left side of the screen.

import Foundation
import MessageKit

class ChatViewController: MessagesViewController {

    private lazy var loader:UIView = {
        return createActivityIndicator(UIScreen.main.focusedView ?? self.view)
    }()

    @IBOutlet weak var topView: UIView!

    let imageView : UIImageView = {
        let iv = UIImageView()
        iv.image = UIImage(named:"backgroundImg")
        iv.contentMode = .scaleAspectFill
        return iv
    }()

    var userId = NSNumber()
    var providerId = NSNumber()
    var rideId = NSNumber()

    var timer = Timer()


    override func viewDidLoad() {
        super.viewDidLoad()

        member = Member(name: "User", color: .headingGold)
        messagesCollectionView.messagesDataSource = self
        messagesCollectionView.messagesLayoutDelegate = self
        messageInputBar.delegate = self
        messagesCollectionView.messagesDisplayDelegate = self


        var topSafeAreaHeight: CGFloat = 0
        var bottomSafeAreaHeight: CGFloat = 0

        let window = UIApplication.shared.windows[0]
        if #available(iOS 11.0, *) {
            let safeFrame = window.safeAreaLayoutGuide.layoutFrame
            topSafeAreaHeight = safeFrame.minY
            bottomSafeAreaHeight = safeFrame.maxY

        } else {
            topSafeAreaHeight = 10
        }

        self.topView.frame = CGRect(x: 10, y: topSafeAreaHeight, width: self.view.frame.size.width-20, height: 60)
        self.topView.layer.cornerRadius = 10
        self.messagesCollectionView.contentInset = UIEdgeInsets(top: topView.frame.maxY, left: 0, bottom: 70, right: 0)
        messagesCollectionView.backgroundView = imageView

        func backgroundColor(for message: MessageType, at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> UIColor {
            return isFromCurrentSender(message: message) ? UIColor.myGold : UIColor.headingGold
        }
        getChatHistory()
        self.timer = Timer.scheduledTimer(timeInterval: 6.0, target: self, selector: #selector(getChatHistory), userInfo: nil, repeats: true)
    }

    override func viewDidAppear(_ animated: Bool) {
        view.bringSubviewToFront(topView)
    }


    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(true)
        timer.invalidate()
    }


    @objc func getChatHistory(){


        self.messages = []
        let request = NSMutableURLRequest(url: NSURL(string: "\(ServiceConstants.baseUrl+ServiceConstants.MD_GET_CHAT)?request_id=\("\(self.rideId)")&user_id=\(self.userId)")! as URL)


        request.httpMethod = "GET"


        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")
        request.addValue("XMLHttpRequest", forHTTPHeaderField: "X-Requested-With")



        let tokenStr:NSString = UserDefaults.standard.value(forKey: "tokentype") as! NSString
        let accessStr:NSString = UserDefaults.standard.value(forKey: "accesstoken") as! NSString
        let str = NSString(format: "%@ %@", tokenStr, accessStr) as String
        request.addValue(str, forHTTPHeaderField: "Authorization")


        let session = URLSession.shared

        //            self.loader.isHidden = false


        let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in

            //                DispatchQueue.main.async {
            //                    self.loader.isHidden = true
            //
            //                }


            if (error != nil) {
                print(error!)
            } else {
                let httpResponse = response as? HTTPURLResponse
                print(httpResponse!)
                do {
                    if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
                        print(jsonResult)

                        let messagesArray = jsonResult["messages"] as! NSArray

                         for dictVal  in messagesArray
                         {
                           if let str = dictVal as? [String:AnyObject]
                           {
                            let msg = str["message"] as! String
                            let type = str["type"] as! String
                            self.member = Member(name: type, color: .myGold)


                             let newMessage = Message(
                                member: self.member,
                                 text: msg,
                                 messageId: UUID().uuidString)

                         //   self.messageCallback(newMessage)
                            self.messages.append(newMessage)


                            }
                        }

                        DispatchQueue.main.async{
                            self.messagesCollectionView.reloadData()
                            self.messagesCollectionView.scrollToBottom(animated: true)
                        }

                    }
                } catch let error as NSError {
                    print(error.localizedDescription)
                }

            }
        })

        dataTask.resume()


    }

    func sendMsg(msg:String){


        let parameters:[String:String] = ["user_id":"\(userId)","provider_id":"\(providerId)","request_id":"\(rideId)","type":"up","message":"\(msg)"]

        let url = URL(string: ServiceConstants.baseUrl + ServiceConstants.MD_SEND_CHAT_MSG)!

        let session = URLSession.shared

        var request = URLRequest(url: url)

        request.httpMethod = "POST"

        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")
        request.addValue("XMLHttpRequest", forHTTPHeaderField: "X-Requested-With")


        let tokenStr:NSString = UserDefaults.standard.value(forKey: "tokentype") as! NSString
        let accessStr:NSString = UserDefaults.standard.value(forKey: "accesstoken") as! NSString
        let str = NSString(format: "%@ %@", tokenStr, accessStr) as String
        request.addValue(str, forHTTPHeaderField: "Authorization")


        do{
            request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)

        }catch let error
        {
            print(error.localizedDescription)
        }

            self.loader.isHidden = false

        let task = session.dataTask(with: request, completionHandler: {data, response, error in

            DispatchQueue.main.async {
                self.loader.isHidden = true

            }

            print(response as Any)

            guard error == nil else{return}
            guard let data = data else{return}

            do{
               if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String:Any]
                {
                    print(json)

                }
            }catch let error
            {
                print(error.localizedDescription)
            }




        })
        task.resume()


    }

    var messages: [Message] = []
    var member: Member!


    @IBAction func backBtnAction(_ sender: Any) {
         dismiss(animated: true, completion: nil)
    }

}

extension ChatViewController: MessagesDataSource {


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

    func currentSender() -> Sender {
        return Sender(id: member.name, displayName: member.name)
    }


    func messageForItem(
        at indexPath: IndexPath,
        in messagesCollectionView: MessagesCollectionView) -> MessageType {

        return messages[indexPath.section]
    }

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

        return 12
    }

    func messageTopLabelAttributedText(
        for message: MessageType,
        at indexPath: IndexPath) -> NSAttributedString? {

        return NSAttributedString(
            string: message.sender.displayName,
            attributes: [.font: UIFont.systemFont(ofSize: 12)])
    }
}


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

        return 0
    }
}
extension ChatViewController: MessagesDisplayDelegate {
    func configureAvatarView(
        _ avatarView: AvatarView,
        for message: MessageType,
        at indexPath: IndexPath,
        in messagesCollectionView: MessagesCollectionView) {

        let message = messages[indexPath.section]
        let color = message.member.color
        avatarView.backgroundColor = color
    }
}
extension ChatViewController: MessageInputBarDelegate {
    func messageInputBar(
        _ inputBar: MessageInputBar,
        didPressSendButtonWith text: String) {

        sendMsg(msg: text)

        member = Member(name: "up", color: .myGold)


        let newMessage = Message(
            member: member,
            text: text,
            messageId: UUID().uuidString)


        messages.append(newMessage)
        inputBar.inputTextView.text = ""
        messagesCollectionView.reloadData()
        messagesCollectionView.scrollToBottom(animated: true)
    }
}
struct Member {
    let name: String
    let color: UIColor
}

struct Message {
    let member: Member
    let text: String
    let messageId: String
}


extension Message: MessageType {
    var sender: Sender {
        return Sender(id: member.name, displayName: member.name)
    }

    var sentDate: Date {
        return Date()
    }

    var kind: MessageKind {
        return .text(text)
    }
}

This is my class for chatViewController and this is my first experience with messageKit. I might be missing something simple or trivial..

1 Answers1

0

The main function that determines alignment is,

func currentSender() -> Sender {
     return Sender(id: member.name, displayName: member.name)
}

In this case, member.name is the identifier to recognize own messages.

The primary provider of that data is initialized as,

member = Member(name: "User", color: .headingGold)

But as you insert a new message it got changed to causing logic for alignment to change,

member = Member(name: "up", color: .myGold) // why change global variable?

In this case, if a member with name: "up" sends a text it switches sides. Better refactor the entire codebase and maintain better id for current and counterpart users.

Follow, official Doc implementation for reference.

tanmoy
  • 1,276
  • 1
  • 10
  • 28