diff --git a/lib/chatview.dart b/lib/chatview.dart index 0b68057a..c1e4c0a5 100644 --- a/lib/chatview.dart +++ b/lib/chatview.dart @@ -37,7 +37,7 @@ export 'src/extensions/extensions.dart' show MessageTypes; export 'src/models/models.dart'; export 'src/utils/chat_view_locale.dart'; export 'src/utils/package_strings.dart'; -export 'src/values/enumeration.dart'; +export 'src/values/enumeration.dart' hide ChatViewListSortBy; export 'src/values/typedefs.dart'; export 'src/widgets/chat_view.dart'; export 'src/widgets/chat_view_appbar.dart'; diff --git a/lib/src/controller/chat_list_view_controller.dart b/lib/src/controller/chat_list_view_controller.dart index cd53dfcb..540ae806 100644 --- a/lib/src/controller/chat_list_view_controller.dart +++ b/lib/src/controller/chat_list_view_controller.dart @@ -24,6 +24,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import '../models/chat_view_list_item.dart'; +import '../values/enumeration.dart'; import '../values/typedefs.dart'; class ChatViewListController { @@ -31,7 +32,21 @@ class ChatViewListController { required List initialChatList, required this.scrollController, this.disposeOtherResources = true, + bool sortEnable = true, + ChatSorter? chatSorter, }) { + chatListStream = _chatListStreamController.stream.map( + (chatMap) { + final chatList = chatMap.values.toList(); + if (sortEnable) { + chatList.sort( + chatSorter ?? ChatViewListSortBy.pinFirstByPinTime.sort, + ); + } + return chatList; + }, + ); + final chatListLength = initialChatList.length; final chatsMap = { @@ -64,10 +79,7 @@ class ChatViewListController { _chatListStreamController = StreamController>.broadcast(); - late final Stream> chatListStream = - _chatListStreamController.stream.map( - (chatMap) => chatMap.values.toList(), - ); + late final Stream> chatListStream; /// Adds a chat to the chat list. void addChat(ChatViewListItem chat) { diff --git a/lib/src/extensions/extensions.dart b/lib/src/extensions/extensions.dart index b6fe61d4..c8f8d36c 100644 --- a/lib/src/extensions/extensions.dart +++ b/lib/src/extensions/extensions.dart @@ -220,3 +220,30 @@ extension BuildContextExtension on BuildContext { ChatBubbleConfiguration? get chatBubbleConfig => chatListConfig.chatBubbleConfig; } + +/// Extension methods for nullable [DateTime] objects. +/// +/// Provides utility methods for comparing nullable [DateTime] instances. +extension NullableDateTimeExtension on DateTime? { + /// Compares this nullable [DateTime] with another nullable [other]. + /// + /// Returns: + /// - `0` if both dates are null or occur at the same moment. + /// - A negative value if this date is null (considered earlier) + /// or occurs before [other]. + /// - A positive value if [other] is null (considered later) + /// or occurs after this date. + int compareWith(DateTime? other) { + final a = this; + final b = other; + if (a == null && b == null) { + return 0; + } else if (a == null) { + return -1; + } else if (b == null) { + return 1; + } else { + return a.compareTo(b); + } + } +} diff --git a/lib/src/values/enumeration.dart b/lib/src/values/enumeration.dart index 1b13e51b..1f294a7d 100644 --- a/lib/src/values/enumeration.dart +++ b/lib/src/values/enumeration.dart @@ -25,6 +25,8 @@ import 'package:chatview_utils/chatview_utils.dart'; import 'package:flutter/material.dart'; +import '../extensions/extensions.dart'; +import '../models/models.dart'; import '../utils/package_strings.dart'; enum ShowReceiptsIn { all, lastMessage } @@ -183,3 +185,46 @@ enum PinStatus { unpinned => Icons.push_pin_outlined, }; } + +/// Enum for different chat list sorting options (for internal use only) +enum ChatViewListSortBy { + /// No sorting applied. + none, + + /// Pin chats first (sorted by pin time), then unpinned by message date/time + pinFirstByPinTime; + + int sort(ChatViewListItem chat1, ChatViewListItem chat2) { + switch (this) { + case none: + return 0; + case pinFirstByPinTime: + final isChatAPinned = chat1.settings.pinStatus.isPinned; + final isChatBPinned = chat2.settings.pinStatus.isPinned; + + // 1. Pinned chats first + if (isChatAPinned && !isChatBPinned) return -1; + if (!isChatAPinned && isChatBPinned) return 1; + + // 2. Sort pinned chats by pinTime descending (latest first) + if (isChatAPinned && isChatBPinned) { + final pinTimeA = chat1.settings.pinTime; + final pinTimeB = chat2.settings.pinTime; + if (pinTimeA != null && pinTimeB != null) { + return pinTimeB.compareTo(pinTimeA); + } + // If one has null pinTime, treat it as older + if (pinTimeA == null && pinTimeB != null) return 1; + if (pinTimeA != null && pinTimeB == null) return -1; + } + + // 3. Sort unpinned chats by message date/time (newest first) + if (!isChatAPinned && !isChatBPinned) { + final chatBCreateAt = chat2.lastMessage?.createdAt; + return chatBCreateAt.compareWith(chat1.lastMessage?.createdAt); + } + + return 0; + } + } +} diff --git a/lib/src/values/typedefs.dart b/lib/src/values/typedefs.dart index def8933b..187a5578 100644 --- a/lib/src/values/typedefs.dart +++ b/lib/src/values/typedefs.dart @@ -132,3 +132,7 @@ typedef ChatViewListTileBuilder = Widget Function( typedef UserAvatarBuilder = Widget Function(ChatViewListItem chat); typedef UserNameBuilder = Widget Function(ChatViewListItem chat); typedef TrailingBuilder = Widget Function(ChatViewListItem chat); +typedef ChatSorter = int Function( + ChatViewListItem chat1, + ChatViewListItem chat2, +);