Search code examples
swiftwatchkit

Loading specific json message_ids according to the selected indexPath


Goal:
When I select a message from the list of chat messages in the MessageListController with didSelectRowAt, I want the opened chat session in the next ChatDetailController to match the same conversation that was selected. Obviously.

I'm working with WatchKit but it's the same thing in this iOS image. The message with Sophia is selected and the chat with Sophia opens. enter image description here
I want to pass the json "message_id" i.e. the chatMessageId property from my model. I'm already passing the chatMessageId from the MessageModelto the ChatDetailController with this line presentController(withName: "ChatDetailController", context: messageContext)

Here is a print out of the passed data using messageContext.

Passed context: Optional(HTWatch_Extension.MessageModel(partner: "9859", nickname: "Marco", message: "Have you seen is dog?", city: "Madrid", countryBadgeImageURL: https://i.sstatic.net/0Z3ZO.jpg, messageListImageURL: https://i.sstatic.net/0Z3ZO.jpg, chatMessageId: "Tva9d2OJyWHRC1AqEfKjclRwXnlRDQ", status: "offline"))

What's the next step? How do I tell the ChatDetailController to populate its table with the conversation that matches the row that was selected?

MessageListController

// ...code...

let messageObject = [MessageModel]()
//var chatObject = [ChatModel]()

// ...code...

override func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) {

    var messageContext = messageObject[rowIndex]
    var chatContext = chatObject[rowIndex]

    do {
        guard let fileUrl = Bundle.main.url(forResource: "Chats", withExtension: "json") else {
            print("File could not be located")
            return
        }
        let data = try Data(contentsOf: fileUrl)
        let decoder = JSONDecoder()

        let msg = try decoder.decode([ChatModel].self, from: data)
        self.chatObject = msg

    } catch let error {
        print(error)
    }

    // I got part of this line from a previous question, but these property types do not match.
    // No matter what chatObject I create I cannot access it/assign it. 
    // Also I do not want to mutate messageContext which Xcode is telling me to do.
    messageContext.chatMessageId = (chatObject as AnyObject).filter { (dictionaryTemp:[String:String]) -> Bool in
        return dictionaryTemp["message_id"] == chatContext.chatMessageId
    } 

    // WatchKit's model presentation method.
    presentController(withName: "ChatDetailController", context: messageContext)
}

ChatDetailController

var chats: [ChatModel] = []

    var messageModel: MessageModel? {
        didSet {
            guard let model = messageModel else { return }             
            partnerLabel.setText(model.nickname)             
        }
    }

    override func awake(withContext context: Any?) {
        super.awake(withContext: context)

        if let message = context as? MessageModel {

            self.messageModel = message
            print("Passed context: \(String(describing: messageModel))")
        } else {
            print("Passed context error: \(String(describing: context))")
        }

        do {
            guard let fileUrl = Bundle.main.url(forResource: "Chats", withExtension: "json") else {
                print("File could not be located")
                return
            }
            let data = try Data(contentsOf: fileUrl)
            let decoder = JSONDecoder()

            let msg = try decoder.decode([ChatModel].self, from: data)
            self.chats = msg

        } catch let error {
            print(error)
        }

        DispatchQueue.main.async(execute: {

            self.setupTable(chatMessageArray: self.chats as [AnyObject])
        })      
    }

ChatModel

public struct ChatModel: Codable {
// ... other properties
public var chatMessageId: String

enum CodingKeys: String, CodingKey {
    // ... other cases
    case chatMessageId = "message_id"
}

init (message:String , fromId:String, toID : String, imgUrl : URL?, chatMessageId : String) {
    // ... other properties
    self.chatMessageId = chatMessageId
   }    
  }
 // .... decoders etc
}

MessageModel

public struct MessageModel: Codable {
    // ...
    public var chatMessageId: String

enum CodingKeys: String, CodingKey {
    // ... other cases
    case chatMessageId = "message_id"
}
// ... init/decoders etc
}

Messages.json

[
  {
    "userid": "4444",
    "nickname": "Marco",
    "online_status": "offline",
    "message": "Have you seen his dog?",
    "city": "Madrid",
    "flag_url": "https://i.sstatic.net/0Z3ZO.jpg",
    "creationDate": "2016-02-22 15:18:40",
    "avatar_url": "https://i.sstatic.net/0Z3ZO.jpg",
    "message_id": "Tva9d2OJyWHRC1AqEfKjclRwXnlRDQ" // different id
  },
  {
      "userid": "12121",
      "nickname": "Tom",
      "online_status": "online",
      "message": "Where is the pizza shop?",
      "city": "Kyoto",
      "flag_url": "https://i.sstatic.net/0Z3ZO.jpg",
      "creationDate": "2016-02-22 15:18:40",
      "avatar_url": "https://i.sstatic.net/0Z3ZO.jpg",
      "message_id": "EnotMkk8REEd0DHGvUgnd45wBap80E" // different id
  }
]

Chats.json

2 conversations containing 2 messages each. Each conversation has a unique fromId (partner), toID (myself), and unique message_id.

[
  {
    "fromId": "zz1234skjksmsjdfwe2zz",
    "toId": "qq43922sdkfjsfmmxdfqq",
    "messageText": "Have you seen is dog?",
    "imageUrl": "https://i.sstatic.net/0Z3ZO.jpg",
    "message_id": "Tva9d2OJyWHRC1AqEfKjclRwXnlRDQ", // conversation 1  - same message id as the 1st message in Messages.josn with nickname Marco.
    "read": "true"                                      
  },
  {
      "fromId": "zz1234skjksmsjdfwe2zz",
      "toId": "qq43922sdkfjsfmmxdfqq",
      "messageText": "Yes I have. It's cute.",
      "imageUrl": "https://i.sstatic.net/0Z3ZO.jpg",
      "message_id": "Tva9d2OJyWHRC1AqEfKjclRwXnlRDQ", // conversation 1
      "read": "true"
  },
  {
      "fromId": "bb888skjaaasjdfwe2333",
      "toId": "qq43922sdkfjsfmmxdfqq",
      "messageText": "What kind of pizza do you want?",
      "imageUrl": "https://i.sstatic.net/0Z3ZO.jpg",
      "message_id": "EnotMkk8REEd0DHGvUgnd45wBap80E", // conversation 2 - same message id as the 2nd message in Messages.josn with nickname Tom.
      "read": "true"
  },
  {
      "fromId": "bb888skjaaasjdfwe2333",
      "toId": "qq43922sdkfjsfmmxdfqq",
      "messageText": "I like ham & pineapple pizza.",
      "imageUrl": "https://i.sstatic.net/0Z3ZO.jpg",
      "message_id": "EnotMkk8REEd0DHGvUgnd45wBap80E", // conversation 2
      "read": "true"
  }
]

Solution

  • let msg = try decoder.decode([ChatModel].self, from: data)
    self.chats = msg
    

    You are storing all chat data contained in Chats.json into chats property.

    To filter chats, try replacing second line like below

    self.chats = msg.filter { chat in
        return chat.chatMessageId == self.messageModel.chatMessageId
    }
    

    or, while I don't know why all chats are contained in single json file, it will be better to separate json file into multiple files for each chat like Chat-Tva9d2OJyWHRC1AqEfKjclRwXnlRDQ.json.

    I hope this will help.