convokit_flutter_ui 0.2.2 copy "convokit_flutter_ui: ^0.2.2" to clipboard
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.

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 #

Standard ConvoKit conversation list and chat 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 #

Branded ConvoKit customer support interface

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

Compact operations #

Compact ConvoKit operations interface

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.

0
likes
150
points
157
downloads

Documentation

API reference

Publisher

verified publisherconvokit.app

Weekly Downloads

Extensible, plug-and-play Flutter UI components for ConvoKit conversations and messaging.

Topics

#chat #messaging #realtime #ui

License

Apache-2.0 (license)

Dependencies

convokit_flutter, flutter

More

Packages that depend on convokit_flutter_ui