Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/chatview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
20 changes: 16 additions & 4 deletions lib/src/controller/chat_list_view_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,29 @@ 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 {
ChatViewListController({
required List<ChatViewListItem> 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 = {
Expand Down Expand Up @@ -64,10 +79,7 @@ class ChatViewListController {
_chatListStreamController =
StreamController<Map<String, ChatViewListItem>>.broadcast();

late final Stream<List<ChatViewListItem>> chatListStream =
_chatListStreamController.stream.map(
(chatMap) => chatMap.values.toList(),
);
late final Stream<List<ChatViewListItem>> chatListStream;

/// Adds a chat to the chat list.
void addChat(ChatViewListItem chat) {
Expand Down
27 changes: 27 additions & 0 deletions lib/src/extensions/extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
45 changes: 45 additions & 0 deletions lib/src/values/enumeration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down Expand Up @@ -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;
}
}
}
4 changes: 4 additions & 0 deletions lib/src/values/typedefs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
);