Data Source
Need to implement channel information data source Channel Information Data Source
Channel Information
Get Channel Information
Copy
// Get channel information
WKIM.shared.channelManager.getChannel(String channelID, int channelType);
Force Refresh Channel Information
Copy
// Force refresh channel information
WKIM.shared.channelManager.fetchChannelInfo(String channelID, int channelType)
Events
Listen for Channel Update Events
Copy
// Listen for channel refresh events
WKIM.shared.channelManager.addOnRefreshListener('key', (wkChannel) {
// Refresh corresponding channel information
});
// Remove listener
WKIM.shared.channelManager.removeOnRefreshListener('key');
The key is a unique identifier for the listener, can be any string. The same key must be used when adding and removing listeners.
Common Methods
Copy
// Batch save channel information
WKIM.shared.channelManager.addOrUpdateChannels(List<WKChannel> channelList);
// Search
WKIM.shared.channelManager.search(String keyword);
Complete Channel Management Example
Copy
class ChannelManager {
static final ChannelManager _instance = ChannelManager._internal();
factory ChannelManager() => _instance;
ChannelManager._internal();
final Map<String, WKChannel> _channelCache = {};
final StreamController<WKChannel> _channelUpdateController = StreamController.broadcast();
// Stream for UI to listen
Stream<WKChannel> get channelUpdateStream => _channelUpdateController.stream;
void initialize() {
_setupChannelListener();
}
void _setupChannelListener() {
// Listen for channel refresh
WKIM.shared.channelManager.addOnRefreshListener('global', (wkChannel) {
_handleChannelUpdate(wkChannel);
});
}
void _handleChannelUpdate(WKChannel channel) {
final channelKey = '${channel.channelID}_${channel.channelType}';
_channelCache[channelKey] = channel;
// Notify listeners
_channelUpdateController.add(channel);
}
// Get channel with caching
WKChannel? getChannelWithCache(String channelID, int channelType) {
final channelKey = '${channelID}_$channelType';
// First check cache
if (_channelCache.containsKey(channelKey)) {
return _channelCache[channelKey];
}
// Get from SDK
final channel = WKIM.shared.channelManager.getChannel(channelID, channelType);
if (channel != null) {
_channelCache[channelKey] = channel;
return channel;
}
// Trigger network request
fetchChannelInfo(channelID, channelType);
return null;
}
// Force refresh channel information
void fetchChannelInfo(String channelID, int channelType) {
WKIM.shared.channelManager.fetchChannelInfo(channelID, channelType);
}
// Batch save channels
void saveChannels(List<WKChannel> channels) {
WKIM.shared.channelManager.addOrUpdateChannels(channels);
// Update cache
for (var channel in channels) {
final channelKey = '${channel.channelID}_${channel.channelType}';
_channelCache[channelKey] = channel;
}
}
// Search channels
List<WKChannel> searchChannels(String keyword) {
return WKIM.shared.channelManager.search(keyword);
}
// Get channel display name
String getChannelDisplayName(WKChannel channel) {
return channel.channelRemark.isNotEmpty
? channel.channelRemark
: (channel.channelName.isNotEmpty ? channel.channelName : channel.channelID);
}
// Check if channel is online
bool isChannelOnline(WKChannel channel) {
return channel.online == 1;
}
// Check if channel is muted
bool isChannelMuted(WKChannel channel) {
return channel.mute == 1;
}
// Check if channel is pinned
bool isChannelPinned(WKChannel channel) {
return channel.top == 1;
}
// Get channel type text
String getChannelTypeText(int channelType) {
switch (channelType) {
case WKChannelType.personal:
return 'Personal';
case WKChannelType.group:
return 'Group';
default:
return 'Unknown';
}
}
// Get channel avatar URL
String getChannelAvatarUrl(WKChannel channel) {
if (channel.avatar.isNotEmpty) {
final cacheKey = channel.avatarCacheKey.isNotEmpty ? '?v=${channel.avatarCacheKey}' : '';
return '${channel.avatar}$cacheKey';
}
return _getDefaultAvatar(channel.channelID);
}
String _getDefaultAvatar(String channelID) {
return 'https://ui-avatars.com/api/?name=$channelID&background=random';
}
// Format last offline time
String formatLastOfflineTime(int lastOffline) {
if (lastOffline == 0) return 'Never';
final date = DateTime.fromMillisecondsSinceEpoch(lastOffline * 1000);
final now = DateTime.now();
final difference = now.difference(date);
if (difference.inMinutes < 1) return 'Just now';
if (difference.inMinutes < 60) return '${difference.inMinutes} minutes ago';
if (difference.inHours < 24) return '${difference.inHours} hours ago';
if (difference.inDays < 7) return '${difference.inDays} days ago';
return '${date.month}/${date.day}/${date.year}';
}
// Get device flag text
String getDeviceFlagText(int deviceFlag) {
switch (deviceFlag) {
case 0: return 'APP';
case 1: return 'WEB';
case 2: return 'PC';
default: return 'Unknown';
}
}
// Check if channel allows invites
bool canInviteMembers(WKChannel channel) {
return channel.invite == 1;
}
// Check if channel has receipt enabled
bool hasReceiptEnabled(WKChannel channel) {
return channel.receipt == 1;
}
// Check if channel is a robot
bool isRobotChannel(WKChannel channel) {
return channel.robot == 1;
}
// Clear channel cache
void clearChannelCache() {
_channelCache.clear();
}
void dispose() {
_channelUpdateController.close();
WKIM.shared.channelManager.removeOnRefreshListener('global');
}
}
Data Structure Description
Copy
class WKChannel {
String channelID = "";
int channelType = WKChannelType.personal;
String channelName = "";
// Channel remark (channel's remark name, personal remark for individuals, group alias for groups)
String channelRemark = "";
int showNick = 0;
// Whether pinned
int top = 0;
// Whether saved in contacts
int save = 0;
// Do not disturb
int mute = 0;
// Forbidden
int forbidden = 0;
// Invite confirmation
int invite = 0;
// Channel status [1: normal 2: blacklist]
int status = 1;
// Whether followed 0: not followed (stranger) 1: followed (friend)
int follow = 0;
// Whether deleted
int isDeleted = 0;
// Creation time
String createdAt = "";
// Update time
String updatedAt = "";
// Channel avatar
String avatar = "";
// Version
int version = 0;
// Extension fields
dynamic localExtra;
// Whether online
int online = 0;
// Last offline time
int lastOffline = 0;
// Last offline device flag
int deviceFlag = 0;
// Whether receipt message
int receipt = 0;
// Robot
int robot = 0;
// Category [service: customer service]
String category = "";
String username = "";
String avatarCacheKey = "";
dynamic remoteExtraMap;
String parentChannelID = "";
int parentChannelType = 0;
}
UI Integration Example
Copy
class ChannelInfoWidget extends StatefulWidget {
final String channelID;
final int channelType;
const ChannelInfoWidget({
Key? key,
required this.channelID,
required this.channelType,
}) : super(key: key);
@override
_ChannelInfoWidgetState createState() => _ChannelInfoWidgetState();
}
class _ChannelInfoWidgetState extends State<ChannelInfoWidget> {
WKChannel? _channel;
late StreamSubscription<WKChannel> _channelSubscription;
@override
void initState() {
super.initState();
_loadChannelInfo();
_setupChannelListener();
}
void _loadChannelInfo() {
_channel = ChannelManager().getChannelWithCache(widget.channelID, widget.channelType);
if (mounted) setState(() {});
}
void _setupChannelListener() {
_channelSubscription = ChannelManager().channelUpdateStream.listen((channel) {
if (channel.channelID == widget.channelID && channel.channelType == widget.channelType) {
setState(() {
_channel = channel;
});
}
});
}
@override
void dispose() {
_channelSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (_channel == null) {
return const Center(child: CircularProgressIndicator());
}
return Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(
ChannelManager().getChannelAvatarUrl(_channel!),
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
ChannelManager().getChannelDisplayName(_channel!),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 4),
Text(
ChannelManager().getChannelTypeText(_channel!.channelType),
style: TextStyle(
color: Colors.grey[600],
),
),
],
),
),
if (ChannelManager().isChannelOnline(_channel!))
Container(
width: 12,
height: 12,
decoration: const BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
),
),
],
),
const SizedBox(height: 16),
_buildInfoRow('Status', ChannelManager().isChannelOnline(_channel!) ? 'Online' : 'Offline'),
if (!ChannelManager().isChannelOnline(_channel!))
_buildInfoRow('Last Seen', ChannelManager().formatLastOfflineTime(_channel!.lastOffline)),
_buildInfoRow('Muted', ChannelManager().isChannelMuted(_channel!) ? 'Yes' : 'No'),
_buildInfoRow('Pinned', ChannelManager().isChannelPinned(_channel!) ? 'Yes' : 'No'),
if (ChannelManager().isRobotChannel(_channel!))
_buildInfoRow('Type', 'Robot'),
],
),
),
);
}
Widget _buildInfoRow(String label, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: TextStyle(
color: Colors.grey[600],
),
),
Text(
value,
style: const TextStyle(
fontWeight: FontWeight.w500,
),
),
],
),
);
}
}

