relatica/lib/screens/notifications_screen.dart

224 wiersze
7.2 KiB
Dart

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<void> _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,
);