I have an existing GroupedListView
that I want to convert to (or replace with) an Expandable
widget. My data source is from Firebase Firestore.
My code is extremely messy of all the "trying to figure it out" cases, so I will keep that as a last resort to keep the post as clean as possible. It kind of looks like this:
List<String> _headers = [];
List<Map<String, dynamic>> = [];
List finalList = [];
await FirebaseFirestore.instance.collection('collection').get().then((snapshot){
for(final document in snapshot.docs){
if(!_headers.contains(document.data()['headerDate'])){
_headers.add(document.data()['headerDate']);
}
}
});
await FirebaseFirestore.instance.collection('collection').get().then((snapshot){
for(headerItem in _headers){
List<Map<String, dynamic>> tempData = [];
for(final document in snapshot.docs){
if(document.data()['headerDate'] == headerItem){
tempData.add([{'name': document.data()['name'], 'idNo': document.data()['idNo'], document.data()['amount']});
}
}
finalList.add([headerItem, tempData]);
}
});
After this I am pretty much stuck and have no idea how to map the data under each headerItem
to be displayed in an expandable group.
Is it safe to follow this structure or is there a possibility that I may get unordered results? Also, is there a cleaner way to write this code I currently have?
Thanks for your help with this!
Edits:
I am still not able to get this right. This is my implementation of how I understand it.
My code for the model:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:collection/collection.dart';
class AttendanceData {
static final _collection =
FirebaseFirestore.instance.collection('attendance2').withConverter(
fromFirestore: _fromFirestore,
toFirestore: _toFirestore,
);
final String headerDate;
final String tagName;
final String tagId;
final String workerType;
final String teamName;
final bool clockedIn;
final String timeIn;
final String timeOut;
final String employeeId;
AttendanceData(
{required this.tagName,
required this.tagId,
required this.workerType,
required this.teamName,
required this.clockedIn,
required this.timeIn,
required this.timeOut,
required this.employeeId,
required this.headerDate});
static AttendanceData _fromFirestore(
DocumentSnapshot<Map<String, dynamic>> snapshot,
SnapshotOptions? options,
) =>
AttendanceData.fromSnapshot(snapshot);
static Map<String, dynamic> _toFirestore(
AttendanceData assignment,
SetOptions? options,
) =>
assignment.toFirestore();
factory AttendanceData.fromSnapshot(
DocumentSnapshot<Map<String, dynamic>> snapshot,
) {
final staffData = snapshot.data();
return AttendanceData(
headerDate: staffData?['headerDate'],
tagName: staffData?['tag_name'],
tagId: staffData?['tag_id'],
workerType: staffData?['worker_type'],
teamName: staffData?['team_name'],
clockedIn: staffData?['clockedIn'],
timeIn: staffData?['timeIn'],
timeOut: staffData?['timeOut'],
employeeId: staffData?['employeeId'],
);
}
Map<String, dynamic> toFirestore() {
return {
'headerDate': headerDate,
'tag_name': tagName,
'tag_id': tagId,
'worker_type': workerType,
'team_name': teamName,
'clockedIn': clockedIn,
'timeIn': timeIn,
'timeOut': timeOut,
'employeeId': employeeId,
};
}
static Stream<QuerySnapshot<AttendanceData>> snapshots() =>
_collection.snapshots();
Map<String, List<dynamic>> groupByHeaderDate(collectionData) {
return groupBy(collectionData, (collection) => collection.headerDate);
}
}
And then in the StreamBuilder
StreamBuilder(
stream: AttendanceData.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return staffData.keys.map((collection) =>
ExpansionTile(
title: collection.headerDate,
subtitle: collection.tagName
)).toList();