As I was unaware that ListTiles exists I implemented the following from scratch:
My widget-structure looks like this:
- StudiesItemWidget (equals scaffold of widget, contains the following three)
- StudiesItemDuration (equals leading number)
- StudiesItemDescription (equals main body of widget, containing description + date)
- StudiesItemRemove (equals trailing icon, on pressed should remove containing item from list)
Here's the relevant code:
Provider for items containing the data for the widgets:
class StudyProvider with ChangeNotifier {
List<StudiesItem> _studiesItemList = [
/*StudiesItem(duration: 100, subject: 'AM', date: DateTime.now()),
StudiesItem(duration: 100, subject: 'AM', date: DateTime.now()),
StudiesItem(duration: 100, subject: 'POS', date: DateTime.now()),
StudiesItem(duration: 100, subject: 'DBI', date: DateTime.now()),*/
];
void addItem(StudiesItem studiesItem) {
_studiesItemList.add(studiesItem);
notifyListeners();
}
List<StudiesItem> get studiesItems {
return List.unmodifiable(_studiesItemList);
}
}
Main studies-item-widget:
class StudiesItemWidget extends StatelessWidget {
final StudiesItem studiesItem;
const StudiesItemWidget({
Key? key,
required this.studiesItem
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Card(
elevation: 5,
child: Container(
width: MediaQuery.of(context).size.width * 0.95,
height: MediaQuery.of(context).size.height * 0.075,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.all(Radius.circular(4))),
child: Chip(
label: Row(
children: [
StudiesItemDuration(timeAmount: studiesItem.duration),
StudiesItemDescription(subject: studiesItem.subject, date: studiesItem.date),
StudiesItemRemove(containingWidget: this)
],
),
backgroundColor: Colors.white,
shape: BeveledRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(4)),
),
),
),
);
}
}
Widget responsible for deletion:
class StudiesItemRemove extends StatelessWidget {
final StudiesItemWidget containingWidget;
const StudiesItemRemove({
required this.containingWidget,
super.key,
});
@override
Widget build(BuildContext context) {
var studiesItems = Provider.of<StudyProvider>(context).studiesItems;
return Expanded(
child: Container(
alignment: Alignment.centerRight,
child: IconButton(
onPressed: () {
studiesItems.remove(containingWidget.studiesItem); // ToDo: fix
},
icon: Icon(Icons.delete)
),
),
);
}
}
In case this is relevant, the list of widgets in the homepage gets built using the following snippet:
var studyProvider = Provider.of<StudyProvider>(context, listen: true);
...
body: Column(
children: [
(studyProvider.studiesItems.isEmpty) ? EmptyStudiesText() : BarChartWidget(),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: studyProvider.studiesItems.length,
itemBuilder: (context, index) {
return StudiesItemWidget(studiesItem: studyProvider.studiesItems[index]);
},
),
),
],
),
Clicking the icon doesn't do anything. As not even printing "remove pressed" on pressed I believe the method doesn't get called at all. Passing the function in different ways (not sure I said that correctly but I mean: "() { code(); } or () => code()") also doesn't make a difference.
Can someone help me out? Thanks
Note: I just changed the remove-call to directly call the providers removeItem function (still doesn't work):
onPressed: () {
studiesItemProvider.removeItem(containingWidget.studiesItem); // ToDo: fix
},
...
bool removeItem(StudiesItem studiesItem) {
var success = _studiesItemList.remove(studiesItem);
notifyListeners();
return success;
}
Second Note: As per request, here is my StudiesItem class:
class StudiesItem {
int duration;
final String subject;
final DateTime date;
StudiesItem({
required this.duration,
required this.subject,
required this.date,
});
StudiesItem.clone(StudiesItem original):
this(
subject: original.subject,
duration: original.duration,
date: original.date
);
@override
String toString() {
return 'StudiesItem{duration: $duration, subject: $subject, date: $date}';
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is StudiesItem &&
runtimeType == other.runtimeType &&
duration == other.duration;
@override
int get hashCode => duration.hashCode;
static StudiesItem mergeItems(StudiesItem item1, StudiesItem item2) {
assert(item1 != item2);
return StudiesItem(
duration: item1.duration + item2.duration,
subject: item1.subject,
date: item1.date
);
}
}
The mergeItems function is used in another (fully working) code-segment to summarize the total data. It should not interfere with the rest of the app.