steve228uk / MessengerKit

:speech_balloon: A UI framework for building messenger interfaces on iOS
MIT License
1.48k stars 129 forks source link

NSFetchedResultsController and sections #11

Closed machukas closed 5 years ago

machukas commented 6 years ago

Hi @steve228uk,

First of all thanks for this super easy to use library!

I am using it with a NSFetchedResultsController, and I am struggling myself trying to get by free the messages grouped by username after ordered by timestamp, but I am not succeeding.

If I provide the date as sort descriptor, and the user as sectionNameKeyPath, it groups the messages by user, so I get numberOfUsers sections, and ordered by timeStamp inside, but that's not what I want; I want by date, but grouped by user just if the messages are in a sequence, like your example.

I guess you (or someone) has faced this problem before, I hope haha.

Thanks in advance

sjoness commented 5 years ago

Hey @machukas, when you initially fetch your messages (I assume you fetch what's stored locally and then you handle anything incoming later), you could process them with a function like this:

func fetchComments() {
    do {
        try frc.performFetch()

        if let messages = frc.fetchedObjects {
            self.addMessages(messages)
        }
    } catch {
        print(error.localizedDescription)
    }
}

public func addMessages(_ messages: [MSGMessage]) {
    collectionView.performBatchUpdates({
        comments.forEach { comment in
            id += 1

            if let lastSection = self.messages.last, let lastMessage = lastSection.last, lastMessage.user.displayName == message.user.displayName {
                self.messages[self.messages.count - 1].append(message)
                let sectionIndex = self.messages.count - 1
                let itemIndex = self.messages[sectionIndex].count - 1
                self.collectionView.insertItems(at: [IndexPath(item: itemIndex, section: sectionIndex)])
            } else {
                self.messages.append([message])
                let sectionIndex = self.messages.count - 1
                self.collectionView.insertSections([sectionIndex])
            }
        }
    }, completion: { (_) in
        self.collectionView.scrollToBottom(animated: true)
        self.collectionView.layoutTypingLabelIfNeeded()
    })
}

You could then do the same thing with a similar method that takes a single comment arguments, when you send or receive a message:

override func inputViewPrimaryActionTriggered(inputView: MSGInputView) {
    addMessage(inputView.message)
}
AraTechES commented 5 years ago

Hey @sjoness, thanks for replying.

What's self.messages? Are you not using the frc.object(at:) as dataSource?

sjoness commented 5 years ago

@AraTechES a suggestion would be to fetch the messages once and then store the results in a separate property so that you can manipulate the order of the messages. In this example you would use the messages property as the dataSource.

machukas commented 5 years ago

Understood, thanks man.

dan007b3 commented 5 years ago

Hey @machukas, I have been trying to figure this thing out but I'm completely stuck. How did you implement this?

machukas commented 5 years ago

To be honest, I didn't. I had to use FRC as a requisite, so I couldn't go with sjoness suggestion.