MessageListViewModel

Previously, our XML and Compose message list ViewModels used the low level client directly to make API calls and enable user interaction. In order to make our code more reliable and the maintenance of our codebase easier, we introduced a layer of shared code between the two message list ViewModels. That layer is represented by a class called MessageListController.

Using the ViewModelFactory

If you’re using our MessagesViewModelFactory, you’ll notice that the experience remains mostly the same along with a few changed parameters:

public class MessagesViewModelFactory(
    private val context: Context,
    private val channelId: String,
    private val messageId: String? = null,
    private val parentMessageId: String? = null,
    private val chatClient: ChatClient = ChatClient.instance(),
    private val clientState: ClientState = chatClient.clientState,
    private val mediaRecorder: StreamMediaRecorder = DefaultStreamMediaRecorder(context.applicationContext),
    private val fileToUriConverter: (File) -> String = { file -> file.toUri().toString() },
    private val messageLimit: Int = MessageListController.DEFAULT_MESSAGES_LIMIT,
    private val clipboardHandler: ClipboardHandler =
        ClipboardHandlerImpl(context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager),
    private val enforceUniqueReactions: Boolean = true,
    private val maxAttachmentCount: Int = AttachmentConstants.MAX_ATTACHMENTS_COUNT,
    private val maxAttachmentSize: Long = AttachmentConstants.MAX_UPLOAD_FILE_SIZE,
    private val showSystemMessages: Boolean = true,
    private val deletedMessageVisibility: DeletedMessageVisibility = DeletedMessageVisibility.ALWAYS_VISIBLE,
    private val messageFooterVisibility: MessageFooterVisibility = MessageFooterVisibility.WithTimeDifference(),
    private val dateSeparatorHandler: DateSeparatorHandler = DateSeparatorHandler.getDefaultDateSeparatorHandler(),
    private val threadDateSeparatorHandler: DateSeparatorHandler =
        DateSeparatorHandler.getDefaultThreadDateSeparatorHandler(),
    private val messagePositionHandler: MessagePositionHandler = MessagePositionHandler.defaultHandler(),
) : ViewModelProvider.Factory

The highlighted parameters have been added and the parameter navigateToThreadViaNotification: Boolean has been removed as navigating to thread messages via push notifications is the default behavior in v6.

  • clientState: Represents the current state of the SDK.
  • clipboardHandler: Used for copying messages.
  • dateSeparatorHandler: Determines the visibility of date separators inside the message list.
  • threadDateSeparatorHandler: Determines the visibility of date separators inside the message list when the list is in thread mode.
  • messagePositionHandler: Determines the position of the message inside the group.

Parameters showDateSeparators: Boolean and dateSeparatorThresholdMillis: Long have been removed in favor of the new date separator handlers which allow for greater flexibility.

Instantiating the ViewModel

We recommend that you instantiate the model using MessagesViewModelFactory, however if you want to instantiate it yourself, then you’ll notice its signature has changed.

Previously, the ViewModel had the following signature:

 public class MessageListViewModel(
     public val chatClient: ChatClient,
     private val channelId: String,
     private val clipboardHandler: ClipboardHandler,
     private val messageLimit: Int = DefaultMessageLimit,
     private val enforceUniqueReactions: Boolean = true,
     private val showDateSeparators: Boolean = true,
     private val showSystemMessages: Boolean = true,
     private val dateSeparatorThresholdMillis: Long = TimeUnit.HOURS.toMillis(DateSeparatorDefaultHourThreshold),
     private val deletedMessageVisibility: DeletedMessageVisibility = DeletedMessageVisibility.ALWAYS_VISIBLE,
     private val messageFooterVisibility: MessageFooterVisibility = MessageFooterVisibility.WithTimeDifference(),
     private val messageId: String? = null,
     private val navigateToThreadViaNotification: Boolean = false,
 ) : ViewModel()

Currently, the ViewModel holds only a single parameter:

public class MessageListViewModel(
    private val messageListController: MessageListController,
) : ViewModel()

MessageListController

The controller has now been made the driving part behind MessageListViewModel. In turn, this means that the parameters necessary to adjust the functioning of the ViewModel have been moved to the controller:

public class MessageListController(
    private val cid: String,
    private val clipboardHandler: ClipboardHandler,
    private val messageId: String? = null,
    private val parentMessageId: String? = null,
    public val messageLimit: Int = DEFAULT_MESSAGES_LIMIT,
    private val chatClient: ChatClient = ChatClient.instance(),
    private val clientState: ClientState = chatClient.clientState,
    private val deletedMessageVisibility: DeletedMessageVisibility = DeletedMessageVisibility.ALWAYS_VISIBLE,
    private val showSystemMessages: Boolean = true,
    private val messageFooterVisibility: MessageFooterVisibility = MessageFooterVisibility.WithTimeDifference(),
    private val enforceUniqueReactions: Boolean = true,
    private val dateSeparatorHandler: DateSeparatorHandler = DateSeparatorHandler.getDefaultDateSeparatorHandler(),
    private val threadDateSeparatorHandler: DateSeparatorHandler =
        DateSeparatorHandler.getDefaultThreadDateSeparatorHandler(),
    private val messagePositionHandler: MessagePositionHandler = MessagePositionHandler.defaultHandler(),
)

You’ll notice that these parameters seem familiar, this is because all of them are passed down to the controller by MessagesViewModelFactory and have been covered in the section addressing the changes made to the ViewModel factory.

© Getstream.io, Inc. All Rights Reserved.