From 2c9357741f3fd26cb7a817f9e9e2dba37ee244f1 Mon Sep 17 00:00:00 2001 From: Hank Grabowski Date: Sat, 19 Nov 2022 14:16:46 -0500 Subject: [PATCH] Add notification clearing capability (server side not working) --- lib/friendica_client.dart | 8 ++++ lib/globals.dart | 47 +++++++++++++++++++++ lib/screens/notifications_screen.dart | 54 +++++++++++++++++++++---- lib/services/notifications_manager.dart | 18 +++++++++ 4 files changed, 120 insertions(+), 7 deletions(-) diff --git a/lib/friendica_client.dart b/lib/friendica_client.dart index 5884c0c..2f4dfb5 100644 --- a/lib/friendica_client.dart +++ b/lib/friendica_client.dart @@ -46,6 +46,14 @@ class FriendicaClient { }); } + FutureResult clearNotifications() async { + final url = 'https://$serverName/api/v1/notifications/clear'; + final request = Uri.parse(url); + _logger.finest(() => 'Clearing unread notifications'); + final response = await _postUrl(request, {}); + return response.mapValue((value) => true); + } + FutureResult, ExecError> getUserTimeline( {String userId = '', int page = 1, int count = 10}) async { _logger.finest(() => 'Getting user timeline for $userId'); diff --git a/lib/globals.dart b/lib/globals.dart index 8d54766..ffb6041 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -1,6 +1,53 @@ +import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:uuid/uuid.dart'; final getIt = GetIt.instance; String randomId() => const Uuid().v4().toString(); + +Future showConfirmDialog(BuildContext context, String caption) { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: Text(caption), + actions: [ + ElevatedButton( + child: const Text('OK'), + onPressed: () { + Navigator.pop(context, true); // showDialog() returns true + }, + ), + ], + ); + }, + ); +} + +Future showYesNoDialog(BuildContext context, String caption) { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + title: Text(caption), + actions: [ + ElevatedButton( + child: const Text('Yes'), + onPressed: () { + Navigator.pop(context, true); // showDialog() returns true + }, + ), + ElevatedButton( + child: const Text('No'), + onPressed: () { + Navigator.pop(context, false); // showDialog() returns false + }, + ), + ], + ); + }, + ); +} diff --git a/lib/screens/notifications_screen.dart b/lib/screens/notifications_screen.dart index ed0c706..f85d71d 100644 --- a/lib/screens/notifications_screen.dart +++ b/lib/screens/notifications_screen.dart @@ -3,7 +3,9 @@ import 'package:provider/provider.dart'; import '../controls/app_bottom_nav_bar.dart'; import '../controls/notifications_control.dart'; +import '../globals.dart'; import '../services/notifications_manager.dart'; +import '../utils/snackbar_builder.dart'; class NotificationsScreen extends StatelessWidget { const NotificationsScreen({super.key}); @@ -12,24 +14,62 @@ class NotificationsScreen extends StatelessWidget { Widget build(BuildContext context) { final manager = context.watch(); final notifications = manager.notifications; + late final String title; + late final Widget body; if (notifications.isEmpty) { manager.updateNotifications(); - } - return Scaffold( - appBar: AppBar( - title: Text('Notifications'), - ), - body: ListView.separated( + title = 'Notifications'; + body = Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text('No notifications'), + ], + )); + } else { + final unreadCount = notifications.where((e) => !e.seen).length; + title = 'Notifications ($unreadCount)'; + body = ListView.separated( itemBuilder: (context, index) { return NotificationControl(notification: notifications[index]); }, separatorBuilder: (context, index) { return Divider(); }, - itemCount: notifications.length), + itemCount: notifications.length); + } + + return Scaffold( + appBar: AppBar( + title: Text(title), + actions: [ + IconButton( + onPressed: () async => _clearAllNotifications(context, manager), + icon: Icon(Icons.clear_all), + ), + ], + ), + body: RefreshIndicator( + onRefresh: () async { + await manager.updateNotifications(); + }, + child: body, + ), bottomNavigationBar: AppBottomNavBar( currentButton: NavBarButtons.notifications, ), ); } + + Future _clearAllNotifications( + BuildContext context, NotificationsManager manager) async { + final confirmed = + await showYesNoDialog(context, 'Clear all notifications?'); + if (confirmed == true) { + final message = (await manager.markAllAsRead()).fold( + onSuccess: (_) => 'Marked all notifications as read', + onError: (error) => 'Error marking notifications: $error'); + buildSnackbar(context, message); + } + } } diff --git a/lib/services/notifications_manager.dart b/lib/services/notifications_manager.dart index 1cce713..1c5bc0d 100644 --- a/lib/services/notifications_manager.dart +++ b/lib/services/notifications_manager.dart @@ -42,6 +42,7 @@ class NotificationsManager extends ChangeNotifier { return result.errorCast(); } + _notifications.clear(); for (final n in result.value) { _notifications[n.id] = n; } @@ -71,4 +72,21 @@ class NotificationsManager extends ChangeNotifier { notifyListeners(); return Result.ok(notifications.first); } + + FutureResult, ExecError> markAllAsRead() async { + final auth = getIt(); + final clientResult = auth.currentClient; + if (clientResult.isFailure) { + _logger.severe('Error getting Friendica client: ${clientResult.error}'); + return clientResult.errorCast(); + } + + final client = clientResult.value; + final result = await client.clearNotifications(); + if (result.isFailure) { + return result.errorCast(); + } + + return updateNotifications(); + } }