Skip to main content

Events and listeners

Nexconn Chat UI exposes EngineProvider, ChannelProvider, and ChatProvider as Flutter notifiers. The default pages update their own UI state, while these listeners let your app add analytics, notifications, routing, badges, and other side effects.

Engine events

EngineProvider bridges global SDK state from NCEngine. It exposes connection, message, deletion, typing, channel sync, unread count, server time, failed-message tracking, and local notification state.

Dart
final engineProvider = context.read<EngineProvider>();

engineProvider.connectionStatusNotifier.addListener(() {
debugPrint('${engineProvider.connectionStatus}');
});

engineProvider.receivedMessageNotifier.addListener(() {
final message = engineProvider.receivedMessageNotifier.value;
debugPrint('Received: ${message?.messageId}');
});

For message-specific side effects, register an async listener and remove it from the same owning object.

Dart
late final NexconnAsyncMessageReceivedListener messageListener;

messageListener = (message) async {
await analytics.logEvent(name: 'message_received');
};

engineProvider.addAsyncMessageReceivedListener(messageListener);
engineProvider.removeAsyncMessageReceivedListener(messageListener);

In a StatefulWidget, register listeners in initState or didChangeDependencies and remove the same callback in dispose.

Dart
class BadgeSyncState extends State<BadgeSync> {
late final EngineProvider engineProvider;
late final NexconnAsyncMessageReceivedListener messageListener;


void initState() {
super.initState();
engineProvider = context.read<EngineProvider>();
messageListener = (message) async {
await syncBadgeCount();
};
engineProvider.addAsyncMessageReceivedListener(messageListener);
}


void dispose() {
engineProvider.removeAsyncMessageReceivedListener(messageListener);
super.dispose();
}
}

Channel updates

ChannelProvider owns the channel list state for ChannelPage. It listens to EngineProvider.channelRefreshNotifier and reloads when channel data should refresh.

Dart
final channelProvider = context.read<ChannelProvider>();

channelProvider.addListener(() {
debugPrint('Channels: ${channelProvider.channels.length}');
debugPrint('Unread: ${channelProvider.engineProvider.totalUnreadCount}');
});

await channelProvider.reload();
await channelProvider.loadMore();

Chat callbacks

ChatPageConfig exposes send hooks and an async received-message hook. The default page still updates the list; use these callbacks for side effects.

Dart
ChatPageConfig(
onBeforeSendMessage: (channel, params) async {
return channel.channelId.isNotEmpty;
},
onAfterSendMessage: (channel, params, message, error) async {
debugPrint('Sent: ${message?.messageId}');
},
onAsyncMessageReceived: (context, message) async {
debugPrint('Received: ${message.messageId}');
},
);

ChatProvider state

ChatProvider owns message loading, selection, search, reference state, unread tips, and send operations for a BaseChannel.

Dart
final chatProvider = context.read<ChatProvider>();

chatProvider.addListener(() {
debugPrint('Messages: ${chatProvider.messages.length}');
debugPrint('Selected: ${chatProvider.selectedMessages.length}');
});

await chatProvider.loadInitialMessages();
await chatProvider.sendText('Hello');

Page-level taps

Use ChannelPage and ChatPage callbacks when the side effect is tied to a specific user action.

Dart
ChannelPage(
onItemTap: (channel, index, context) {
openChannelChatPage(context, channel);
},
);

ChatPage(
channel: channel,
onMessageTap: (message) {
debugPrint('Tapped: ${message.messageId}');
},
);