Skip to content

Persisted Controller 🔄

A controller in flutter_chat_ui acts as the source of truth for your chat data, primarily managing the messages. When implementing a persisted controller, understanding how your data source handles order is crucial. There are primarily two types of data sources to consider: ordered and non-ordered.

An ordered data source maintains a specific sequence for its elements. A simple example is an array, which is utilized by the InMemoryChatController provided by the flutter_chat_core package.

With an array-based (and thus ordered) data source, operations are straightforward:

  • You can insert messages at any specific index.
  • You can update messages at any specific index.
  • You can simply return the array from the messages getter.

However, it’s important to note that the InMemoryChatController is, by its nature, not persisted. While simple to work with, its data will be lost when the application session ends.

Non-Ordered Data Sources (Common for Persisted Controllers)

Section titled “Non-Ordered Data Sources (Common for Persisted Controllers)”

For persisted controllers, you will most likely be working with some form of database.

Databases with Implicit Ordering (e.g., Auto-Increment Keys)

Section titled “Databases with Implicit Ordering (e.g., Auto-Increment Keys)”

If your chosen database supports inherent ordering (for instance, through auto-incrementing primary keys), and you don’t anticipate needing to insert messages into the middle of an existing conversation, this will work similarly to the InMemoryChatController. You won’t be able to insert or update at a specific index, but you can still simply return the ordered data directly from the database.

Many databases will not guarantee any specific order when you retrieve data. They operate without auto-increment keys or an intrinsic sense of sequence.

In this scenario:

  • You typically add new messages to the database without specifying a position.
  • You cannot reliably implement functions like insertMessage({int? index}) or insertAllMessages({int? index}) because there’s no stable concept of an “index” directly from the database.

Recommended Approach:

  1. Insertion: Add messages to the database as they arrive.
  2. Retrieval (messages getter):
    • Fetch all relevant messages from your data source.
    • Sort these messages based on a reliable key before returning them. A common and effective choice is a createdAt timestamp, serialized to milliseconds for precise ordering.
  3. Benefits:
    • This approach consistently ensures the correct message order in your UI.
    • It robustly handles offline-first scenarios. When syncing with a backend, new and historical messages can be seamlessly integrated and correctly ordered because the sorting logic remains consistent.

A practical example of this approach using Hive CE can be found in the example project - HiveChatController.