fetchPrevious method
Future<List<BaseMessage> >
fetchPrevious({
- required dynamic onSuccess(
- List<
BaseMessage> message
- List<
- required dynamic onError(
- CometChatException excep
Returns a list of BaseMessage object fetched after putting the filters.
Android Reference: MessagesRequest.fetchPrevious()
Migration Note: Migrated from platform channels to native Dart.
Uses MessageRepository for backend communication.
Fetches older messages (prepend direction).
Implementation
Future<List<BaseMessage>> fetchPrevious(
{required Function(List<BaseMessage> message)? onSuccess,
required Function(CometChatException excep)? onError}) async {
try {
// 1. Validate request parameters
// **Android Reference:** MessagesRequest.fetchPrevious() → validateMessageRequest()
final validationError = _validateMessageRequest();
if (validationError != null) {
if (onError != null) onError(validationError);
return [];
}
// 2. Check updatesOnly without updatedAfter
// **Android Reference:** if (updatesOnly && updatedAfter == -1)
final int? updatedAfterLong = updatedAfter != null
? updatedAfter!.millisecondsSinceEpoch ~/ 1000
: null;
if ((updatesOnly ?? false) && updatedAfterLong == null) {
final error = CometChatException(
'ERR_UPDATESONLY_WITHOUT_UPDATEDAFTER',
'updatedAfter must be set when updatesOnly is true',
'updatedAfter must be set when updatesOnly is true',
);
if (onError != null) onError(error);
return [];
}
// 3. Check hasPrevious flag — return empty list if no more messages
// **Android Reference:** MessagesRequest.fetchPrevious() hasPrevious check
if (!_hasPrevious) {
if (onSuccess != null) onSuccess([]);
return [];
}
// 4. Check limit does not exceed MAX_LIMIT
// **Android Reference:** Each fetch method checks limit <= MAX_LIMIT
if ((limit ?? 0) > (maxLimit ?? 100)) {
final error = CometChatException(
'ERR_LIMIT_EXCEEDED',
'Limit cannot exceed $maxLimit',
'Limit cannot exceed $maxLimit',
);
if (onError != null) onError(error);
return [];
}
// 5. Check inProgress flag — return error if already fetching
// **Android Reference:** returns ERROR_REQUEST_IN_PROGRESS to onError
if (_inProgress) {
final error = CometChatException(
'ERR_REQUEST_IN_PROGRESS',
'A fetch request is already in progress',
'A fetch request is already in progress',
);
if (onError != null) onError(error);
return [];
}
// Set inProgress flag before fetch
// **Android Reference:** MessagesRequest.fetchPrevious() line: inProgress = true
_inProgress = true;
// 1. Get SDK instance
final sdk = SdkRegistry.getInstance();
// 2. Get updatedAfter as Unix timestamp (already computed above)
int? updateAfterLong = updatedAfterLong;
// 3. Call repository based on parentMessageId/uid/guid
// **Android Reference:** MessagesRequest.fetchPrevious() routing:
// parentMessageId first, then uid+guid, then uid, then guid, then fallback
late final result;
if (parentMessageId != null && parentMessageId != 0) {
// Threaded messages — checked FIRST per Android SDK
result = await sdk.messages.getThreadedMessages(
parentMessageId.toString(),
limit: limit ?? 30,
affix: 'prepend', // fetchPrevious = prepend (older messages)
timestamp: _timestamp,
messageId: _messageId?.toString(),
unread: unread,
hideMessagesFromBlockedUsers: hideMessagesFromBlockedUsers,
searchKeyword: searchKeyword,
updatedAfter: updateAfterLong,
updatesOnly: updatesOnly,
categories: categories,
types: types,
hideDeleted: hideDeleted,
tags: tags,
withTags: withTags,
interactionGoalCompleted: interactionGoalCompletedOnly,
mentionsWithTagInfo: _mentionsWithTagInfo,
mentionsWithBlockedInfo: _mentionsWithBlockedInfo,
hasAttachments: hasAttachments,
hasLinks: hasLinks,
hasMentions: hasMentions,
hasReactions: hasReactions,
mentionedUids: mentionedUids,
attachmentTypes: attachmentTypes,
withParent: withParent,
hideQuotedMessages: hideQuotedMessages,
);
} else if (uid != null &&
uid!.isNotEmpty &&
guid != null &&
guid!.isNotEmpty) {
// User messages in a specific group
// **Android Reference:** fetchMessagesForUserInGroup()
result = await sdk.messages.getUserMessages(
uid!,
limit: limit ?? 30,
affix: 'prepend',
timestamp: _timestamp,
messageId: _messageId?.toString(),
unread: unread,
hideMessagesFromBlockedUsers: hideMessagesFromBlockedUsers,
searchKeyword: searchKeyword,
updatedAfter: updateAfterLong,
updatesOnly: updatesOnly,
categories: categories,
types: types,
hideReplies: hideReplies,
hideDeleted: hideDeleted,
tags: tags,
withTags: withTags,
interactionGoalCompleted: interactionGoalCompletedOnly,
mentionsWithTagInfo: _mentionsWithTagInfo,
mentionsWithBlockedInfo: _mentionsWithBlockedInfo,
hasAttachments: hasAttachments,
hasLinks: hasLinks,
hasMentions: hasMentions,
hasReactions: hasReactions,
mentionedUids: mentionedUids,
attachmentTypes: attachmentTypes,
hideQuotedMessages: hideQuotedMessages,
);
} else if (uid != null && uid!.isNotEmpty) {
// User messages
result = await sdk.messages.getUserMessages(
uid!,
limit: limit ?? 30,
affix: 'prepend', // fetchPrevious = prepend (older messages)
timestamp: _timestamp,
messageId: _messageId?.toString(),
unread: unread,
hideMessagesFromBlockedUsers: hideMessagesFromBlockedUsers,
searchKeyword: searchKeyword,
updatedAfter: updateAfterLong,
updatesOnly: updatesOnly,
categories: categories,
types: types,
hideReplies: hideReplies,
hideDeleted: hideDeleted,
tags: tags,
withTags: withTags,
interactionGoalCompleted: interactionGoalCompletedOnly,
mentionsWithTagInfo: _mentionsWithTagInfo,
mentionsWithBlockedInfo: _mentionsWithBlockedInfo,
hasAttachments: hasAttachments,
hasLinks: hasLinks,
hasMentions: hasMentions,
hasReactions: hasReactions,
mentionedUids: mentionedUids,
attachmentTypes: attachmentTypes,
hideQuotedMessages: hideQuotedMessages,
);
} else if (guid != null && guid!.isNotEmpty) {
// Group messages
result = await sdk.messages.getGroupMessages(
guid!,
limit: limit ?? 30,
affix: 'prepend', // fetchPrevious = prepend (older messages)
timestamp: _timestamp,
messageId: _messageId?.toString(),
unread: unread,
hideMessagesFromBlockedUsers: hideMessagesFromBlockedUsers,
searchKeyword: searchKeyword,
updatedAfter: updateAfterLong,
updatesOnly: updatesOnly,
categories: categories,
types: types,
hideReplies: hideReplies,
hideDeleted: hideDeleted,
tags: tags,
withTags: withTags,
interactionGoalCompleted: interactionGoalCompletedOnly,
mentionsWithTagInfo: _mentionsWithTagInfo,
mentionsWithBlockedInfo: _mentionsWithBlockedInfo,
hasAttachments: hasAttachments,
hasLinks: hasLinks,
hasMentions: hasMentions,
hasReactions: hasReactions,
mentionedUids: mentionedUids,
attachmentTypes: attachmentTypes,
hideQuotedMessages: hideQuotedMessages,
);
} else {
// All messages
result = await sdk.messages.getMessages(
limit: limit ?? 30,
timestamp: _timestamp,
messageId: _messageId?.toString(),
affix: 'prepend', // fetchPrevious = prepend (older messages)
unread: unread,
hideMessagesFromBlockedUsers: hideMessagesFromBlockedUsers,
searchKeyword: searchKeyword,
updatedAfter: updateAfterLong,
updatesOnly: updatesOnly,
categories: categories,
types: types,
hideReplies: hideReplies,
hideDeleted: hideDeleted,
tags: tags,
withTags: withTags,
interactionGoalCompleted: interactionGoalCompletedOnly,
mentionsWithTagInfo: _mentionsWithTagInfo,
mentionsWithBlockedInfo: _mentionsWithBlockedInfo,
hasAttachments: hasAttachments,
hasLinks: hasLinks,
hasMentions: hasMentions,
hasReactions: hasReactions,
mentionedUids: mentionedUids,
attachmentTypes: attachmentTypes,
hideQuotedMessages: hideQuotedMessages,
);
}
// 4. Update pagination cursor for next fetch
// For prepend (fetchPrevious), we update to the MIN messageId/timestamp
// Reference: Android SDK updateMessageIdAndTimestamp() method
_updatePaginationCursor(result.messages, isAppend: false);
// 5. Update pagination state from response
// **Android Reference:** MessagesRequest.fetchPrevious() pagination state update
_updatePaginationState(result);
// 6. Update hasNext/hasPrevious flags based on page comparison
// **Android Reference:** if (affix==PREPEND && currentPage==totalPages) { hasPrevious=false; hasNext=true; }
if (_currentPage != -1 &&
_totalPages != -1 &&
_currentPage == _totalPages) {
_hasPrevious = false;
_hasNext = true;
}
// Also set hasPrevious=false if no messages returned (safety net)
if (result.messages.isEmpty) {
_hasPrevious = false;
}
// 7. Reset inProgress flag after successful fetch
// **Android Reference:** MessagesRequest.fetchPrevious() line: inProgress = false
_inProgress = false;
// 8. Call callbacks
if (onSuccess != null) {
onSuccess(result.messages);
}
return result.messages;
} on sdk_errors.SdkException catch (sdkEx) {
// Reset inProgress flag on error
_inProgress = false;
// Convert SdkException to CometChatException
final cometChatEx = CometChatException(
sdkEx.code,
sdkEx.details ?? sdkEx.message,
sdkEx.message,
);
if (onError != null) {
onError(cometChatEx);
}
} catch (e) {
// Reset inProgress flag on error
_inProgress = false;
debugPrint("Error: ${e.toString()}");
// Handle unexpected errors
final cometChatEx = CometChatException(
ErrorCode.errorUnhandledException,
e.toString(),
e.toString(),
);
if (onError != null) {
onError(cometChatEx);
}
}
return [];
}