convokit_flutter_ui 0.2.2
convokit_flutter_ui: ^0.2.2 copied to clipboard
Extensible, plug-and-play Flutter UI components for ConvoKit conversations and messaging.
ConvoKit Flutter UI #
Plug-and-play, extensible Flutter UI for the
convokit_flutter SDK. The package provides a
conversation inbox and a complete selected-conversation surface without taking
control away from the host app.
Included #
- SDK-backed and controlled conversation-list components
- Offset pagination with automatic scroll-to-load-more
- Search, archived, participant, predicate, and custom-sort filters
- SDK-backed and controlled conversation components
- Older-message pagination and realtime message, typing, and read events
- Text sending and structured image/file/media rendering
- Default read indicators calculated from participant read positions
- Theme tokens plus builders for every major state and component
- A replaceable client boundary for caching, analytics, offline state, custom authorization, or an alternative state-management layer
The package is deliberately split into two layers:
| Layer | Use when |
|---|---|
ConvoKitConversationList / ConvoKitConversation |
You want working SDK-backed UI with minimal setup. |
ConvoKitConversationListView / ConvoKitConversationView |
Your application already owns state and operations. |
Component gallery #
These are real renders of the package widgets using backend-free fixture data.
The complete, runnable implementation is in
lib/showcase/component_showcase_app.dart,
with widget coverage in
test/component_showcase_test.dart.
Standard components #

The default conversation rows, header, message bubbles, structured file card,
read receipts, and composer. This version also demonstrates onRefresh,
onAddAttachment, readAtByUserId, and reverseMessages: true.
Branded customer support #

The same controlled widgets styled as a support workspace. It replaces only
selected pieces through itemBuilder, headerBuilder, mediaBlockBuilder,
readReceiptBuilder, and composerBuilder.
Compact operations #

A dense dashboard treatment using custom padding, separators, message rows,
typing indicator, and composer, with reverseMessages: false.
Run the public examples repository:
git clone https://github.com/ConvoKitApp/ConvoKit-Flutter-UI-Examples.git
cd ConvoKit-Flutter-UI-Examples
flutter run -d chrome
On Flutter web, append ?variant=standard, ?variant=branded, or
?variant=compact to open a specific configuration directly.
Install #
Add both the core SDK and UI package:
flutter pub add convokit_flutter convokit_flutter_ui
Configure and connect the core SDK before constructing an SDK-backed UI controller. The app's client secret belongs only on the token server; never put it in Flutter.
ConvoKit.configure(
clientId: 'public-client-id',
tokenProvider: (appUserId) => tokenService.issueToken(appUserId),
);
await ConvoKit.connectUser(currentAppUser.id);
The core SDK uses ConvoKit's managed https://api.convokit.app endpoint. Set
backendUrl only for local testing or a self-hosted deployment.
SDK-backed conversations render an outgoing message immediately, reconcile it with the server response and realtime echo, and restore an unchanged draft if the send fails.
Plug-and-play UI #
Use the list at the top level, then open a conversation selected by the user:
class Inbox extends StatelessWidget {
const Inbox({super.key});
@override
Widget build(BuildContext context) {
return ConvoKitConversationList(
onConversationSelected: (conversation) {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => Scaffold(
body: ConvoKitConversation(
conversationId: conversation.id,
onBack: () => Navigator.of(context).pop(),
onAttachmentTap: (context, message, attachment) {
// Open the URL with the host app's browser/download policy.
},
),
),
),
);
},
);
}
}
The list requests the next conversation page near its bottom. The conversation requests older message pages near its oldest edge. Controllers de-duplicate records and ignore stale asynchronous results.
Filtering and pagination #
Own a controller when filters need to change after construction:
final conversations = ConvoKitConversationListController(
pageSize: 25,
initialFilter: const ConvoKitConversationFilter(archived: false),
);
await conversations.setQuery('design');
await conversations.setFilter(
ConvoKitConversationFilter(
participantIds: const {'app_user_42'},
predicate: (conversation) => conversation.description != null,
comparator: (a, b) => b.updatedAt.compareTo(a.updatedAt),
),
);
archived is sent to the SDK. Text, participants, predicates, and ordering are
applied locally. If a local filter produces no result in the current source
page, the controller keeps paging until it finds a match or reaches the end.
For server-side search or cursor translation, provide pageLoader:
final conversations = ConvoKitConversationListController(
pageLoader: (request) async {
return repository.searchConversations(
query: request.filter.query,
limit: request.limit,
offset: request.offset,
);
},
);
UI customization #
The controlled widgets let the host replace only what it needs:
ConvoKitConversationView(
conversation: state.conversation,
messages: state.messages,
currentUserId: state.userId,
readAtByUserId: state.readAtByUserId,
typingUserIds: state.typingUserIds,
onSendMessage: controller.sendText,
onLoadOlder: controller.loadOlder,
hasOlderMessages: state.hasOlder,
headerBuilder: (context, conversation, onBack, onRefresh) {
return MyConversationHeader(conversation: conversation);
},
messageBuilder: (context, message, index, isMine, sender, readers) {
return MyMessageBubble(message: message, readers: readers);
},
mediaBlockBuilder: (context, block, message, isMine) {
return block['type'] == 'poll' ? MyPoll(block: block) : null;
},
composerBuilder: (context, text, isSending, send, addAttachment) {
return MyComposer(controller: text, onSend: send);
},
);
Available replacement points include conversation rows, separators, loading, empty and error states, header, message row, individual media blocks, read receipts, typing indicator, composer, attachment taps, user-name resolution, scroll controllers, padding, thresholds, and list direction.
To style the defaults, install the theme extension:
MaterialApp(
theme: ThemeData(
extensions: const [
ConvoKitUiThemeData.light(),
],
),
home: const Inbox(),
);
Use copyWith to replace individual color and sizing tokens.
Functional customization #
Implement ConvoKitUiClient and pass it to either controller when the UI should
use a repository, cache, offline queue, analytics wrapper, or a custom
authorization policy. DefaultConvoKitUiClient delegates directly to the
existing static ConvoKit SDK.
Externally supplied controllers remain owned by the host and must be disposed there. Controllers created internally by plug-and-play widgets are disposed by the widgets.
Optimistic outgoing rows display Sending… until the backend acknowledges
them. The acknowledged server timestamp is then rendered in the viewer's local
timezone. Custom message builders can use isConvoKitPendingMessage(message)
to present the same state.
Read receipts #
ConvoKitConversationController.state.readAtByUserId stores the latest known
read position from conversation participants and realtime read events.
state.readerIdsFor(message) returns the users whose read timestamp includes
that message. The default outgoing bubble displays one check when delivered and
two checks plus a reader count after another participant has read it. Replace
readReceiptBuilder for avatars, detailed labels, or product-specific rules.
Media #
Default image and file cards tolerate missing URLs, names, and numeric/string
file sizes. onAttachmentTap intentionally delegates opening and downloading
to the host app, where authentication and platform behavior belong. Unknown
structured types receive a safe fallback; return a widget from
mediaBlockBuilder to support custom blocks such as polls, locations, contacts,
audio, or commerce cards.
Verification #
dart format --output=none --set-exit-if-changed lib test
flutter analyze
flutter test
See the public
ConvoKit-Flutter-UI-Examples
repository for runnable default, branded, compact, and SDK-backed application
configurations.