markAsRead static method
- BaseMessage baseMessage, {
- required dynamic onSuccess()?,
- required dynamic onError(
- CometChatException excep
Messages for both user and group conversations can be marked as read using this method.
Ideally, you should mark all the messages as read for any conversation when the user opens the chat window.
messageId The ID of the message above which all messages for a particular conversation are to be marked as read.
receiverId In case of one to one conversation message's sender UID will be the receipt's receiver Id.In case of group conversation message's receiver Id will be the receipt's receiver Id
senderId The UID of the sender of the message
Migration Note: Migrated from platform channels to native Dart implementation. Marks the message and all prior messages as read for that conversation.
Uses RealtimeRepository for WebSocket-based receipt delivery. Behavior and signature remain identical for backward compatibility.
Android Reference: CometChat.markAsRead(BaseMessage message, CallbackListener<Void> listener)
File: chat-sdk-android/.../CometChat.java:3839
Validation (matches Android):
- Message must not be null
- Message sender must not be null
- User must be logged in
- Connection must not be feature throttled
- Settings mode must allow receipts (not LIMITED_TRANSIENT or NO_TRANSIENT)
receiverId Logic (matches Android):
- For groups: Use message.receiverUid
- For users (I sent): Use message.receiverUid
- For users (I received): Use message.sender.uid
Transport (matches Android):
- If WebSocket connected → send via socket (primary)
- If WebSocket disconnected/connecting → send via REST API (fallback)
method could throw PlatformException with error codes specifying the cause
Implementation
static Future<void> markAsRead(BaseMessage baseMessage,
{required Function(String)? onSuccess,
required Function(CometChatException excep)? onError}) async {
try {
// Validation 1: Null sender check (Android behavior)
// Note: baseMessage itself cannot be null due to Dart null safety
if (baseMessage.sender == null) {
final cometChatEx = CometChatException(
'ERROR_INVALID_MESSAGE',
'Invalid message',
'Message sender cannot be null',
);
_errorCallbackHandler(cometChatEx, null, null, onError);
return;
}
// Get SDK instance
final sdk = SdkRegistry.getInstance();
// Validation 3: User logged in check (Android behavior)
final loggedInUser = sdk.auth.getLoggedInUser();
if (loggedInUser == null) {
final cometChatEx = CometChatException(
ErrorCode.errorUserNotLoggedIn,
ErrorMessage.errorMessageUserNotLoggedIn,
'Please login before marking messages as read',
);
_errorCallbackHandler(cometChatEx, null, null, onError);
return;
}
// Validation 4: Connection status check for feature throttled (Android behavior)
// Note: We still check for feature throttled even when using API fallback
final connectionStatus = sdk.realtime.connectionState;
if (connectionStatus == sdk_connection.ConnectionState.featureThrottled) {
final cometChatEx = CometChatException(
'ERROR_RECEIPTS_TEMPORARILY_BLOCKED',
'Receipts temporarily blocked',
'Mark as read not functional in feature-throttled mode',
);
_errorCallbackHandler(cometChatEx, null, null, onError);
return;
}
// Validation 5: Settings mode check (Android behavior)
/* final settings = await sdk.settings.getCachedSettings();
if (settings != null &&
(settings.mode == MODE_LIMITED_TRANSIENT ||
settings.mode == MODE_NO_TRANSIENT)) {
throw CometChatException('ERROR_RECEIPTS_TEMPORARILY_BLOCKED', ...);
}*/
// Determine receiverId based on Android logic
// Reference: CometChat.java:3857-3867
String receiverId;
if (baseMessage.receiverType == "group") {
// For groups: always use message's receiverUid
receiverId = baseMessage.receiverUid;
} else {
// For users: check if I sent the message or received it
if (baseMessage.sender!.uid == loggedInUser.uid) {
// I sent the message → mark as read for the receiver
receiverId = baseMessage.receiverUid;
} else {
// I received the message → mark as read for the sender
receiverId = baseMessage.sender!.uid;
}
}
// Check connection status to decide transport method
// Reference: CometChat.java:4250-4258 - markAsRead(MessageReceipt, CallbackListener)
// Android: if disconnected/connecting → use API, else use WebSocket
final isDisconnectedOrConnecting =
connectionStatus == sdk_connection.ConnectionState.disconnected ||
connectionStatus == sdk_connection.ConnectionState.connecting;
if (isDisconnectedOrConnecting) {
// Use REST API fallback (Android: markAsReadInternal)
// Reference: CometChat.java:10402-10438
await sdk.messages.markAsReadViaApi(
messageId: baseMessage.id,
receiverId: receiverId,
receiverType: baseMessage.receiverType,
);
} else {
// Use WebSocket (primary path)
// Reference: CometChat.java:4255 - rttConnection.markAsRead()
// Create message receipt (matching Android structure)
// Reference: CometChat.java:3856-3871
final receipt = MessageReceipt(
messageId: baseMessage.id,
sender: baseMessage.sender!,
receiverId: receiverId,
receiverType: baseMessage.receiverType,
receiptType: 'read', // MessageReceipt.RECEIPT_TYPE_READ
timestamp: DateTime.now(),
deliveredAt: baseMessage.deliveredAt,
readAt: DateTime.now(),
messageSender: baseMessage.sender!.uid,
);
await sdk.realtime.markAsRead(receipt);
}
// Call success callback
if (onSuccess != null) onSuccess('Message marked as read');
} on SdkException catch (sdkEx) {
// Convert SdkException to CometChatException
final cometChatEx = CometChatException(
sdkEx.code,
sdkEx.details ?? sdkEx.message,
sdkEx.message,
);
_errorCallbackHandler(cometChatEx, null, null, onError);
} catch (e) {
// Handle unexpected exceptions (Android behavior)
// Reference: CometChat.java:3872-3881
final cometChatEx = CometChatException(
ErrorCode.errorUnhandledException,
e.toString(),
'Unhandled exception in markAsRead',
);
_errorCallbackHandler(cometChatEx, null, null, onError);
}
}