Generic Date List View
A powerful, customizable, and high-performance Flutter package that groups and displays items by date. Ideal for chat applications, transaction histories, event timelines, activity logs, and feeds.
✨ Features
- 🚀 Highly Performant & Virtualized: Uses lazy list virtualization instead of rendering groups in heavy columns. Smooth 60/120 FPS scrolling even with thousands of items.
- 📌 Sticky Date Headers: WhatsApp and Telegram-style pinned date headers (
useStickyHeaders: true) powered by native Flutter slivers. - 🕒 Direct
DateTimeor String Extraction: Supports bothextractDateTime(fast, direct) andextractDate(ISO-8601 string, backward-compatible). - 🎨 Custom Date Format & Labels: Custom labels like "Today", "Yesterday", "আজ", "গতকাল", or any localized string via
dateLabelBuilder. - 🛠️ Section Header Styling: Customize badge decoration, text style, padding, dividers, or supply a completely custom widget via
headerBuilder. - ↕️ Ascending & Descending Sorting: Control order for date groups (
sortOrder) and items within groups (itemSortOrder). - 📅 Grouping Granularity: Group items by Day, Week, Month, or Year (
groupBy: GroupGranularity.day | week | month | year). - 📭 Empty State Widget: Provide
emptyWidgetoremptyBuilderwhen the list or search result is empty. - 🔍 Built-in Search & Filtering: Filter list items instantly using
searchQueryandfilterPredicate. - 🔄 Infinite Scrolling / Pagination: Lazy load items seamlessly with
onLoadMoreandisLoadingMore. - 🌐 RTL & Localization Support: Perfectly symmetric bidirectional layout for both LTR and RTL (Arabic, Hebrew, etc.) languages.
📦 Installation
Add this package to your pubspec.yaml:
dependencies:
genericlistwithdate: ^1.0.0
Import it in your Dart code:
import 'package:genericlistwithdate/genericlistwithdate.dart';
🚀 Quick Start
1. Basic Usage (Chat / Messages)
class Message {
final String content;
final DateTime timestamp;
Message(this.content, this.timestamp);
}
class ChatScreen extends StatelessWidget {
final List<Message> messages = [
Message("Hello!", DateTime.now()),
Message("How are you?", DateTime.now().subtract(const Duration(hours: 2))),
Message("See you tomorrow!", DateTime.now().subtract(const Duration(days: 1))),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Chat")),
body: GenericDateListView<Message>(
dataList: messages,
extractDateTime: (m) => m.timestamp,
itemBuilder: (context, message) {
return ListTile(
title: Text(message.content),
subtitle: Text(message.timestamp.toLocal().toString()),
);
},
),
);
}
}
💡 Advanced Examples
2. WhatsApp / Telegram Style Sticky Date Headers
Enable pinned headers that stick to the top as you scroll:
GenericDateListView<Message>(
dataList: messages,
extractDateTime: (m) => m.timestamp,
useStickyHeaders: true,
stickyHeaderHeight: 44.0,
itemBuilder: (context, message) => MessageBubble(message: message),
)
3. Custom Date Label ("Today", "Yesterday", or Bengali/Local)
GenericDateListView<Message>(
dataList: messages,
extractDateTime: (m) => m.timestamp,
dateLabelBuilder: (date) {
final now = DateTime.now();
if (date.day == now.day && date.month == now.month && date.year == now.year) {
return 'আজকের বার্তা'; // Custom Bengali label
}
return '${date.day}-${date.month}-${date.year}';
},
itemBuilder: (context, message) => MessageTile(message: message),
)
4. Custom Header Widget (headerBuilder)
GenericDateListView<Message>(
dataList: messages,
extractDateTime: (m) => m.timestamp,
headerBuilder: (context, date, formattedDate) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 8),
alignment: Alignment.center,
child: Chip(
backgroundColor: Colors.blue.shade100,
label: Text(
formattedDate,
style: TextStyle(fontWeight: FontWeight.bold, color: Colors.blue.shade900),
),
),
);
},
itemBuilder: (context, message) => MessageTile(message: message),
)
5. Group by Month, Week, or Year
GenericDateListView<Transaction>(
dataList: transactions,
extractDateTime: (tx) => tx.date,
groupBy: GroupGranularity.month, // Group items by month!
sortOrder: SortOrder.descending, // Newer months first
itemBuilder: (context, tx) => TransactionTile(transaction: tx),
)
6. Search and Filter
GenericDateListView<Message>(
dataList: messages,
extractDateTime: (m) => m.timestamp,
searchQuery: currentSearchText,
filterPredicate: (item, query) =>
item.content.toLowerCase().contains(query.toLowerCase()),
emptyWidget: const Text("No matching messages found"),
itemBuilder: (context, message) => MessageTile(message: message),
)
7. Pagination / Infinite Scroll
GenericDateListView<Message>(
dataList: messages,
extractDateTime: (m) => m.timestamp,
isLoadingMore: isFetchingMore,
onLoadMore: () {
// Fetch next page of items
fetchNextPage();
},
loadingWidget: const Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: CircularProgressIndicator(),
),
),
itemBuilder: (context, message) => MessageTile(message: message),
)
⚙️ Configuration Properties
| Parameter | Type | Default | Description |
|---|---|---|---|
dataList |
List<T> |
required | The list of data objects. |
extractDateTime |
DateTime Function(T) |
null |
Fast direct DateTime extractor (recommended). |
extractDate |
String Function(T) |
null |
ISO-8601 string extractor (backward-compatible). |
itemBuilder |
Widget Function(BuildContext, T) |
required | Builder for each item. |
useStickyHeaders |
bool |
false |
Enables pinned WhatsApp/Telegram sticky date headers. |
stickyHeaderHeight |
double |
48.0 |
Height for pinned sticky headers. |
dateLabelBuilder |
String Function(DateTime) |
null |
Custom string formatter for date labels. |
headerBuilder |
Widget Function(BuildContext, DateTime, String) |
null |
Custom widget builder for section headers. |
sortOrder |
SortOrder |
SortOrder.ascending |
Sorting direction for date groups (ascending or descending). |
itemSortOrder |
SortOrder? |
sortOrder |
Sorting direction for items within each date group. |
groupBy |
GroupGranularity |
GroupGranularity.day |
Granularity (day, week, month, year). |
emptyWidget |
Widget? |
null |
Widget displayed when list is empty. |
emptyBuilder |
WidgetBuilder? |
null |
Dynamic builder when list is empty. |
searchQuery |
String? |
null |
Search query to filter data. |
filterPredicate |
bool Function(T, String)? |
null |
Predicate matching item against search query. |
onLoadMore |
VoidCallback? |
null |
Callback triggered when scrolling near boundary. |
isLoadingMore |
bool |
false |
Shows loading indicator at list boundary. |
loadingWidget |
Widget? |
null |
Custom loading indicator widget. |
reverse |
bool |
false |
Sets scroll view to reverse mode (useful for chats). |
physics |
ScrollPhysics? |
BouncingScrollPhysics() |
Scroll physics for list. |
controller |
ScrollController? |
null |
ScrollController for the list. |
headerTextStyle |
TextStyle? |
null |
Custom text style for header badge. |
headerDecoration |
BoxDecoration? |
null |
Custom decoration for header badge. |
dividerColor |
Color? |
null |
Color of lines flanking header badge. |
showDividers |
bool |
true |
Whether to display horizontal divider lines. |
🤝 Contributions
Contributions, bug reports, and feature suggestions are always welcome! Feel free to open an issue or submit a pull request on GitHub.
📄 License
This package is licensed under the MIT License. See LICENSE for details.
👤 Author
Earbaj Md Saria
- Email: earbajsaria3@gmail.com
- GitHub: @Earbaj
Libraries
- genericlistwithdate
- A customizable Flutter package that displays items grouped by date.