Add mark all as read action to notifications list

Shows a done_all icon button in the AppBar when the New filter is active
and the list is non-empty, calling the notifications/mark_all_as_old endpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
rzuasti
2026-05-27 12:10:02 -04:00
co-authored by Claude Sonnet 4.6
parent bda7b87cc7
commit 6002597383
2 changed files with 71 additions and 43 deletions
@@ -32,6 +32,20 @@ class _NotificationListState extends State<NotificationList> {
}, },
); );
Future<void> _markAllAsRead(BuildContext context) async {
await BackendAPI.instance.markAllNotificationsAsRead();
_pagingController.refresh();
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('All notifications marked as read'),
behavior: SnackBarBehavior.floating,
showCloseIcon: true,
),
);
}
}
Future<bool> _markAsRead( Future<bool> _markAsRead(
BuildContext context, BuildContext context,
oott_model.Notification item, oott_model.Notification item,
@@ -102,50 +116,59 @@ class _NotificationListState extends State<NotificationList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( // Paginated list start
appBar: AppBar(title: const Text('Notifications')), return PagingListener(
body: controller: _pagingController,
// Paginated list start builder: (context, state, fetchNextPage) => Scaffold(
PagingListener( appBar: AppBar(
controller: _pagingController, title: const Text('Notifications'),
builder: (context, state, fetchNextPage) => CustomScrollView( actions: [
slivers: [ if (_filterChoice == 1 && (state.items?.isNotEmpty ?? false))
// Filters go here IconButton(
SliverToBoxAdapter( onPressed: () => _markAllAsRead(context),
child: Container( icon: const Icon(Icons.done_all),
height: 50, tooltip: 'Mark all as read',
alignment: Alignment.centerRight, ),
child: Wrap( ],
spacing: 8.0, ),
children: [ body: CustomScrollView(
ChoiceChip( slivers: [
label: Text('New'), // Filters go here
selected: _filterChoice == 1, SliverToBoxAdapter(
onSelected: (bool selected) { child: Container(
_filterChoice = 1; height: 50,
_pagingController.refresh(); alignment: Alignment.centerRight,
}, child: Wrap(
), spacing: 8.0,
ChoiceChip( children: [
label: Text('Old'), ChoiceChip(
selected: _filterChoice == 2, label: Text('New'),
onSelected: (bool selected) { selected: _filterChoice == 1,
_filterChoice = 2; onSelected: (bool selected) {
_pagingController.refresh(); _filterChoice = 1;
}, _pagingController.refresh();
), },
ChoiceChip(
label: Text('All'),
selected: _filterChoice == 3,
onSelected: (bool selected) {
_filterChoice = 3;
_pagingController.refresh();
},
),
],
), ),
), ChoiceChip(
label: Text('Old'),
selected: _filterChoice == 2,
onSelected: (bool selected) {
_filterChoice = 2;
_pagingController.refresh();
},
),
ChoiceChip(
label: Text('All'),
selected: _filterChoice == 3,
onSelected: (bool selected) {
_filterChoice = 3;
_pagingController.refresh();
},
),
],
), ),
),
),
PagedSliverList<int, oott_model.Notification>( PagedSliverList<int, oott_model.Notification>(
state: state, state: state,
fetchNextPage: fetchNextPage, fetchNextPage: fetchNextPage,
@@ -231,7 +254,7 @@ class _NotificationListState extends State<NotificationList> {
], ],
), ),
), ),
); );
// Paginated list end // Paginated list end
} }
+5
View File
@@ -76,6 +76,11 @@ class BackendAPI {
await _dio.post('/notifications/$id/mark_as_new'); await _dio.post('/notifications/$id/mark_as_new');
} }
Future<void> markAllNotificationsAsRead() async {
print('About to call /notifications/mark_all_as_old');
await _dio.post('/notifications/mark_all_as_old');
}
Future<List<Notification>> listNotifications(bool? isNew, int offset) async { Future<List<Notification>> listNotifications(bool? isNew, int offset) async {
print('About to call /notifications'); print('About to call /notifications');