I've been trying to get some messages ordered by date, but I'm not getting it working. I have tried different packages like grouped_list and sticky_headers.
With sticky_headers I managed to get a header above every post but that's not what I want. I want to have the messages sorted by day. Like the image below:
Below I have an dataset with de data I get from my API. My intention is to get 40 messages from the API. Those 40 messages are sorted by time only the messages must be grouped by day in the app as the image above.
Edit: After some playing with sticky_header package on flutter. I have now managed to get the headers. Only do not manage to get the messages under the correct header.
Dataset:
[
{
"time": "2020-06-16T10:31:12.000Z",
"message": "P2 BGM-01 HV buiten materieel (Gas lekkage) Franckstraat Arnhem 073631"
},
{
"time": "2020-06-16T10:29:35.000Z",
"message": "A1 Brahmslaan 3862TD Nijkerk 73278"
},
{
"time": "2020-06-16T10:29:35.000Z",
"message": "A2 NS Station Rheden Dr. Langemijerweg 6991EV Rheden 73286"
},
{
"time": "2020-06-15T09:41:18.000Z",
"message": "A2 VWS Utrechtseweg 6871DR Renkum 74636"
},
{
"time": "2020-06-14T09:40:58.000Z",
"message": "B2 5623EJ : Michelangelolaan Eindhoven Obj: ziekenhuizen 8610 Ca CATH route 522 PAAZ Rit: 66570"
}
]
Use collection package to use groupBy function. I hope this snippet will help you to start constructing your UI. You can use ListView widget for list items in each group. Go through DateTime, DateFormat classes to handle date, time values.
separated. In Flutter, you can use ListView. separated to easily create a list view whose items are separated by separators (or dividers). A separator only appears between two list items and never stands before the first or sits after the last item.
First, breakdown your code to get group by date map from your dataset. Then use this map to construct the UI.
Use collection package to use groupBy function.
import "package:collection/collection.dart";
void main() {
final dataSet = [
{
"time": "2020-06-16T10:31:12.000Z",
"message": "Message1",
},
{
"time": "2020-06-16T10:29:35.000Z",
"message": "Message2",
},
{
"time": "2020-06-15T09:41:18.000Z",
"message": "Message3",
},
];
var groupByDate = groupBy(dataSet, (obj) => obj['time'].substring(0, 10));
groupByDate.forEach((date, list) {
// Header
print('${date}:');
// Group
list.forEach((listItem) {
// List item
print('${listItem["time"]}, ${listItem["message"]}');
});
// day section divider
print('\n');
});
}
Output:
2020-06-16:
2020-06-16T10:31:12.000Z, Message1
2020-06-16T10:29:35.000Z, Message2
2020-06-15:
2020-06-15T09:41:18.000Z, Message3
I hope this snippet will help you to start constructing your UI. You can use ListView widget for list items in each group.
Go through DateTime, DateFormat classes to handle date, time values.
There are some dart.pub packages called sticky_grouped_list and grouped_list (mentioned in your question). They have done a good work around group elements by a common property. I have tried sticky_grouped_list and besides I don't have used in your specific scenario it's seems to apply to it, once the Lists can group elements by a dynamic type.
Beyond the appearance, the main functional difference between your code and that example is they have used a DateTime element instead a String as a better manner to group the list. The sticky group list view is interesting due the fact the current date stick on the top of screen when it's rolled down.
instead of using a ListView create a GroupedListView Widget:
GroupedListView<dynamic, String>(
elements: _elements,
groupBy: (element) => element['group'],
groupSeparatorBuilder: (String groupByValue) => Text(groupByValue),
itemBuilder: (context, dynamic element) => Text(element['name']),
order: GroupedListOrder.ASC,
),
With the StickyGroupedListView you also can group by a custom object:
StickyGroupedListView<CustomObject, DateTime>(
elements: pedidos,
order: StickyGroupedListOrder.ASC,
groupBy: (CustomObject element) => DateTime(
element.dateGroup.year,
element.dateGroup.month,
element.dateGroup.day),
groupSeparatorBuilder: (CustomObject element) =>
renderDataCabecalho(element),
itemBuilder: (context, element) {
return _buildPedidoItemView(element, context);
},
),
If it don't apply to your needs may you could get some insights on their approach to group elements by.
If the API supports sorting, obtaining results in the correct order will be the simplest, and most high-performance solution.
You should be able to achieve that by some custom logic on date. Check if two consecutive Dates are same if not add a Text Header in between those list items.
Heres the implementation of above approach.
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
void main() {
final dateString = '2020-06-16T10:31:12.000Z';
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Map> list = [
{
"time": "2020-06-16T10:31:12.000Z",
"message":
"P2 BGM-01 HV buiten materieel (Gas lekkage) Franckstraat Arnhem 073631"
},
{
"time": "2020-06-16T10:29:35.000Z",
"message": "A1 Brahmslaan 3862TD Nijkerk 73278"
},
{
"time": "2020-06-16T10:29:35.000Z",
"message": "A2 NS Station Rheden Dr. Langemijerweg 6991EV Rheden 73286"
},
{
"time": "2020-06-15T09:41:18.000Z",
"message": "A2 VWS Utrechtseweg 6871DR Renkum 74636"
},
{
"time": "2020-06-14T09:40:58.000Z",
"message":
"B2 5623EJ : Michelangelolaan Eindhoven Obj: ziekenhuizen 8610 Ca CATH route 522 PAAZ Rit: 66570"
}
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView.builder(
itemCount: list.length,
itemBuilder: (_, index) {
bool isSameDate = true;
final String dateString = list[index]['time'];
final DateTime date = DateTime.parse(dateString);
final item = list[index];
if (index == 0) {
isSameDate = false;
} else {
final String prevDateString = list[index - 1]['time'];
final DateTime prevDate = DateTime.parse(prevDateString);
isSameDate = date.isSameDate(prevDate);
}
if (index == 0 || !(isSameDate)) {
return Column(children: [
Text(date.formatDate()),
ListTile(title: Text('item $index'))
]);
} else {
return ListTile(title: Text('item $index'));
}
}),
),
);
}
}
const String dateFormatter = 'MMMM dd, y';
extension DateHelper on DateTime {
String formatDate() {
final formatter = DateFormat(dateFormatter);
return formatter.format(this);
}
bool isSameDate(DateTime other) {
return this.year == other.year &&
this.month == other.month &&
this.day == other.day;
}
int getDifferenceInDaysWithNow() {
final now = DateTime.now();
return now.difference(this).inDays;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With