import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:logging/logging.dart'; import '../controls/app_bottom_nav_bar.dart'; import '../controls/notifications_control.dart'; import '../controls/padding.dart'; import '../controls/responsive_max_width.dart'; import '../controls/standard_app_drawer.dart'; import '../controls/standard_appbar.dart'; import '../controls/status_and_refresh_button.dart'; import '../globals.dart'; import '../models/auth/profile.dart'; import '../models/user_notification.dart'; import '../riverpod_controllers/account_services.dart'; import '../riverpod_controllers/networking/network_status_services.dart'; import '../riverpod_controllers/notification_services.dart'; import '../riverpod_controllers/settings_services.dart'; import '../utils/snackbar_builder.dart'; class NotificationsScreen extends ConsumerWidget { static final _logger = Logger('$NotificationsScreen'); const NotificationsScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { _logger.finer('Building'); final profile = ref.watch(activeProfileProvider); const title = 'Notifications'; final loading = ref.watch(notificationsLoadingProvider(profile)); late final Widget body; final actions = [ if (platformIsDesktop) StatusAndRefreshButton( executing: loading, refreshFunction: () async => ref .read(notificationsManagerProvider(profile).notifier) .refreshNotifications(), ), IconButton( onPressed: () async => _clearAllNotifications(context, ref, profile), icon: const Icon(Icons.cleaning_services), ), ]; final hasNoNotifications = !ref.watch(hasAnyNotificationsProvider(profile)); if (hasNoNotifications) { body = RefreshIndicator( onRefresh: () async => ref .read(notificationsManagerProvider(profile).notifier) .refreshNotifications(), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: loading ? [ const Center(child: Text('Loading Notifications')), ] : [ const Center(child: Text('No notifications')), const VerticalPadding(), ElevatedButton( onPressed: () => ref .read(notificationsManagerProvider(profile).notifier) .refreshNotifications(), child: const Text('Load Notifications'), ) ], )), ); } else { final groupNotifications = ref.watch(notificationGroupingSettingProvider); final notificationEntries = groupNotifications ? [ ...orderedNotificationTypes.map((type) => _NotificationsByTypeListElement( profile: profile, type: type, isRead: false)), _NotificationsByReadStatusListElement( profile: profile, isRead: true), ] : [ _NotificationsByReadStatusListElement( profile: profile, isRead: false), _NotificationsByReadStatusListElement( profile: profile, isRead: true), ]; final allEntries = [ TextButton( onPressed: () async { await ref .read(notificationsManagerProvider(profile).notifier) .loadNewerNotifications(); }, child: const Text('Load newer notifications')), ...notificationEntries, TextButton( onPressed: () async { await ref .read(notificationsManagerProvider(profile).notifier) .loadOlderNotifications(); }, child: const Text('Load older notifications')) ]; body = RefreshIndicator( onRefresh: () async => ref .read(notificationsManagerProvider(profile).notifier) .refreshNotifications(), child: ResponsiveMaxWidth( child: ListView.separated( itemBuilder: (_, index) => allEntries[index], separatorBuilder: (_, __) => _standardDivider, itemCount: allEntries.length, ), )); } return Scaffold( appBar: StandardAppBar.build( context, title, withHome: false, withDrawer: true, actions: actions, ), drawer: const StandardAppDrawer(), body: Center( child: Column( children: [ if (loading) const LinearProgressIndicator(), Expanded( child: ResponsiveMaxWidth(child: body), ), ], ), ), bottomNavigationBar: const AppBottomNavBar( currentButton: NavBarButtons.notifications, ), ); } Future _clearAllNotifications( BuildContext context, WidgetRef ref, Profile profile) async { final confirmed = await showYesNoDialog(context, 'Clear all notifications?'); if (confirmed == true) { final message = (await ref .read(notificationsManagerProvider(profile).notifier) .markAllAsRead()) .fold( onSuccess: (_) => 'Marked all notifications as read', onError: (error) => 'Error marking notifications: $error'); if (context.mounted) { buildSnackbar(context, message); } } } } class _NotificationsByTypeListElement extends ConsumerWidget { final Profile profile; final NotificationType type; final bool isRead; const _NotificationsByTypeListElement( {required this.profile, required this.type, required this.isRead}); @override Widget build(BuildContext context, WidgetRef ref) { final notifications = ref.watch(userNotificationsByTypeProvider(profile, type, isRead)); return ListView.separated( primary: false, shrinkWrap: true, itemBuilder: (_, index) => NotificationControl(notification: notifications[index]), separatorBuilder: (_, __) => _standardDivider, itemCount: notifications.length, ); } } class _NotificationsByReadStatusListElement extends ConsumerWidget { final Profile profile; final bool isRead; const _NotificationsByReadStatusListElement( {required this.profile, required this.isRead}); @override Widget build(BuildContext context, WidgetRef ref) { final notifications = ref.watch(allNotificationsProvider(profile, isRead)); return ListView.separated( primary: false, shrinkWrap: true, itemBuilder: (_, index) => NotificationControl(notification: notifications[index]), separatorBuilder: (_, __) => _standardDivider, itemCount: notifications.length, ); } } final orderedNotificationTypes = [ NotificationType.follow_request, NotificationType.follow, NotificationType.direct_message, NotificationType.mention, NotificationType.status, NotificationType.reshare, NotificationType.reblog, NotificationType.favourite, NotificationType.unknown, ]; const _standardDivider = Divider( color: Colors.black54, height: 0.0, );