Skip to main content

Channel list

ChannelPage is the default channel list screen. It renders BaseChannel items from a ChannelProvider and includes loading state, pagination, pull-to-refresh, optional search entry, empty state, swipe actions, long-press actions, unread badges, pinned state, mute state, and default navigation to ChatPage.

UI preview

The following image shows the default channel list page.

Channel list page

Basic usage

ChannelPage creates an internal ChannelProvider when you do not pass one. The page reads EngineProvider from the widget tree, so wrap your app with NexconnChatUIProviders or provide EngineProvider yourself.

Dart
ChannelPage(
onItemTap: (channel, index, context) {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => ChatPage(channel: channel),
),
);
},
);

You can also use the built-in opener. It keeps the same BaseChannel instance and applies the default route fallback when named routes are not configured.

Dart
ChannelPage(
chatPageOpener: (context, channel) {
return openChannelChatPage(context, channel);
},
);

Provide channel data

ChannelProvider loads pages through ChannelsQuery with ChannelsQueryParams. Use channelTypes, pageSize, and channelListDataProcessor to control what the list receives before rendering.

Dart
ChannelPage(
provider: ChannelProvider(
engineProvider: context.read<EngineProvider>(),
channelTypes: const [ChannelType.direct, ChannelType.group],
pageSize: 30,
channelListDataProcessor: (channels) => channels
.where((channel) => channel.channelId.isNotEmpty)
.toList(),
),
);

For static or externally managed lists, construct the provider with initialChannels and update it later with replaceChannels.

Dart
final provider = ChannelProvider(
engineProvider: context.read<EngineProvider>(),
initialChannels: <BaseChannel>[DirectChannel('user_001')],
);

provider.replaceChannels(<BaseChannel>[
DirectChannel('user_001'),
GroupChannel('team_001'),
]);

Channel actions

The default list can pin, unpin, mute, unmute, and delete channels. These actions call ChannelProvider.pinChannel, unpinChannel, muteChannel, unmuteChannel, and deleteChannel.

Use onChannelAction when your app needs confirmation, analytics, or custom behavior before calling the provider.

Dart
ChannelPage(
onChannelAction: (context, channel, action) async {
final provider = context.read<ChannelProvider>();
final error = switch (action) {
ChannelActionType.pin => await provider.pinChannel(channel),
ChannelActionType.unpin => await provider.unpinChannel(channel),
ChannelActionType.mute => await provider.muteChannel(channel),
ChannelActionType.unmute => await provider.unmuteChannel(channel),
ChannelActionType.delete => await provider.deleteChannel(channel),
};

if (error != null && !error.isSuccess) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(error.message ?? 'Channel action failed')),
);
}
},
);

Customize item display

ChannelItemConfig controls the default row. Use display profiles for names and avatars, or provide item builders for full replacement. If the channel list and the default ChatPage should share the same app-owned profile source, set ChannelConfig.profileProvider; row-specific displayProfiles and displayProfileResolver still have higher priority for channel rows.

Dart
ChannelPage(
config: ChannelConfig(
profileProvider: (channel, {message}) async {
final userId = message?.senderUserId ?? channel.channelId;
final profile = await accountRepository.loadUser(userId);
return ChatProfileInfo(
id: userId,
name: profile?.displayName ?? userId,
portraitUri: profile?.avatarUrl,
);
},
listConfig: const ChannelListConfig(
showSearchBar: true,
channelTypes: [ChannelType.direct, ChannelType.group],
),
itemConfig: ChannelItemConfig(
avatarShape: ChannelAvatarShape.circle,
showDirectChannelOnlineStatus: true,
displayProfileResolver: (context, channel) async {
return ChannelDisplayProfile(
displayName: channel.channelId,
avatarUrl: null,
);
},
),
),
);
Dart
ChannelPage(
itemBuilder: (context, channel, config) {
return ListTile(
leading: const CircleAvatar(child: Icon(Icons.tag)),
title: Text(channel.channelId),
subtitle: Text(channel.channelType.name),
);
},
);

For more builders, see Channel page builders.