1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-22 12:59:21 +00:00
comunicmobile/lib/ui/screens/notifications_screen.dart
2022-03-11 17:02:06 +01:00

338 lines
9.6 KiB
Dart

import 'package:comunic/helpers/events_helper.dart';
import 'package:comunic/helpers/groups_helper.dart';
import 'package:comunic/helpers/notifications_helper.dart';
import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/lists/groups_list.dart';
import 'package:comunic/lists/notifications_list.dart';
import 'package:comunic/lists/users_list.dart';
import 'package:comunic/models/notification.dart' as n;
import 'package:comunic/ui/routes/main_route/main_route.dart';
import 'package:comunic/ui/widgets/account_image_widget.dart';
import 'package:comunic/ui/widgets/custom_list_tile.dart';
import 'package:comunic/ui/widgets/safe_state.dart';
import 'package:comunic/utils/date_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/navigation_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';
/// Notifications screen
///
/// @author Pierre HUBERT
enum _Status { LOADING, ERROR, NONE }
enum _PopupMenuActions { DELETE }
class NotificationsScreen extends StatefulWidget {
final bool useSmallDeleteButton;
const NotificationsScreen({
Key? key,
this.useSmallDeleteButton = false,
}) : super(key: key);
@override
_NotificationsScreenState createState() => _NotificationsScreenState();
}
class _NotificationsScreenState extends SafeState<NotificationsScreen> {
NotificationsList? _list;
late UsersList _users;
late GroupsList _groups;
_Status _status = _Status.LOADING;
final _refreshKey = GlobalKey<RefreshIndicatorState>();
void setStatus(_Status s) => setState(() => _status = s);
Future<void> _loadList() async {
setStatus(_Status.LOADING);
try {
final list = await NotificationsHelper().getUnread();
final users = await UsersHelper().getListWithThrow(list.usersIds);
final groups = await GroupsHelper().getListOrThrow(list.groupsIds);
setState(() {
_list = list;
_users = users;
_groups = groups;
});
setStatus(_Status.NONE);
} on Exception catch (e, s) {
print("Exception while getting the list of notifications!");
print("$e, $s");
} on Error catch (e, s) {
print("Error while getting the list of notifications!");
print("$e, $s");
}
}
@override
void initState() {
super.initState();
this.listen<NewNumberNotifsEvent>((d) => _refreshKey.currentState!.show());
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_loadList();
}
@override
Widget build(BuildContext context) {
// Loading status
if (_list == null || _status == _Status.LOADING)
return Center(
child: CircularProgressIndicator(),
);
return Container(
height: double.infinity,
child: Stack(children: [
Container(
height: double.infinity,
child: RefreshIndicator(
key: _refreshKey,
child: _buildBody(),
onRefresh: _loadList,
),
),
// Add conversation button
Positioned(
right: widget.useSmallDeleteButton ? 0.0 : 20.0,
bottom: widget.useSmallDeleteButton ? 0.0 : 20.0,
child: FloatingActionButton(
mini: widget.useSmallDeleteButton,
onPressed: () => _deleteAllNotifications(),
child: Icon(Icons.delete),
),
)
]),
);
}
/// Build body
Widget _buildBody() {
if (_status == _Status.ERROR || _list!.length == 0)
return SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: _buildSingleChildCases(),
);
return ListView(
children: _list!
.map((f) => _NotificationTile(
notification: f,
usersList: _users,
groupsList: _groups,
onDelete: _deleteNotification,
))
.toList(),
);
}
Widget _buildSingleChildCases() {
// In case of error
if (_status == _Status.ERROR)
return buildErrorCard(tr("Could not get the list of notifications!"),
actions: [
MaterialButton(
onPressed: () => _loadList(),
child: Text(tr("Try again".toUpperCase())!),
)
]);
// When there is no notification
if (_list!.length == 0)
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Text(tr("You do not have any notification now.")!),
),
);
throw Error();
}
/// Delete a notification
void _deleteNotification(n.Notification notif) async {
setState(() {
_list!.remove(notif);
});
NotificationsHelper().markSeen(notif);
}
/// Delete all the notifications
void _deleteAllNotifications() async {
if (!await showConfirmDialog(
context: context,
message: tr("Do you really want to delete all your notifications?")))
return;
if (!await NotificationsHelper().deleteAllNotifications()) {
showSimpleSnack(context, tr("Could not delete all your notifications!")!);
return;
}
_refreshKey.currentState!.show();
}
}
class _NotificationTile extends StatelessWidget {
final n.Notification notification;
final UsersList usersList;
final GroupsList groupsList;
final void Function(n.Notification) onDelete;
const _NotificationTile({
Key? key,
required this.notification,
required this.usersList,
required this.groupsList,
required this.onDelete,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final srcUser = usersList.getUser(notification.fromUser);
String message = "${srcUser.fullName} ";
switch (notification.type) {
// Comment
case n.NotificationType.COMMENT_CREATED:
message += tr("posted a comment")!;
break;
// Friendship requests
case n.NotificationType.SENT_FRIEND_REQUEST:
message += tr("sent you a friendship request.")!;
break;
case n.NotificationType.ACCEPTED_FRIEND_REQUEST:
message += tr("accepted your friendship request.")!;
break;
case n.NotificationType.REJECTED_FRIEND_REQUEST:
message += tr("rejected your friendship request.")!;
break;
// Groups membership
case n.NotificationType.SENT_GROUP_MEMBERSHIP_INVITATION:
message += tr("invited you to join the group")!;
break;
case n.NotificationType.ACCEPTED_GROUP_MEMBERSHIP_INVITATION:
message += tr("accepted his invitation to join the group")!;
break;
case n.NotificationType.REJECTED_GROUP_MEMBERSHIP_INVITATION:
message += tr("rejected his invitation to join the group")!;
break;
case n.NotificationType.SENT_GROUP_MEMBERSHIP_REQUEST:
message += tr("sent a request to join the group")!;
break;
case n.NotificationType.ACCEPTED_GROUP_MEMBERSHIP_REQUEST:
message += tr("accepted you request to join the group")!;
break;
case n.NotificationType.REJECTED_GROUP_MEMBERSHIP_REQUEST:
message += tr("rejected your request to join the group")!;
break;
// Generic element creation
case n.NotificationType.ELEM_CREATED:
if (notification.onElemType == n.NotificationElementType.POST)
message += tr("created a new post")!;
break;
case n.NotificationType.ELEM_UPDATED:
// Operation not implemented
break;
}
// Separator
message += " ";
// Notification target
// User page
if (notification.fromContainerType == n.NotificationElementType.USER_PAGE) {
if (notification.fromUser == notification.fromContainerId)
message += tr("on his / her page")!;
else
message += tr("on %user_name%'s page", args: {
"user_name": usersList.getUser(notification.fromContainerId).fullName
})!;
}
// Group page
if (notification.fromContainerType ==
n.NotificationElementType.GROUP_PAGE) {
message += tr("on the group %group%.", args: {
"group": groupsList[notification.fromContainerId]!.displayName
})!;
}
// Group membership
if (notification.onElemType == n.NotificationElementType.GROUP_MEMBERSHIP)
message += groupsList[notification.onElemId]!.displayName;
return CustomListTile(
leading: AccountImageWidget(
user: srcUser,
),
onTap: () => _onTap(context),
title: Text(message),
subtitle: Text(diffTimeFromNowToStr(notification.timeCreate)!),
onLongPressOpenMenu: (position) {
showMenu(context: context, position: position, items: [
PopupMenuItem(
child: Text(tr("Delete")!),
value: _PopupMenuActions.DELETE,
),
]).then(_popupMenuAction);
},
);
}
void _popupMenuAction(_PopupMenuActions? value) {
switch (value) {
case _PopupMenuActions.DELETE:
onDelete(notification);
break;
default:
break;
}
}
void _onTap(BuildContext context) {
if (notification.onElemType == n.NotificationElementType.POST) {
openPostFullScreen(notification.onElemId, context);
} else if (notification.onElemType ==
n.NotificationElementType.FRIENDSHIP_REQUEST) {
openUserPage(userID: notification.fromUser, context: context);
} else if (notification.onElemType ==
n.NotificationElementType.GROUP_MEMBERSHIP) {
MainController.of(context)!.openGroup(notification.onElemId);
} else {
showSimpleSnack(context,
tr("This kind of notification is not supported yet by this application.")!);
return;
}
onDelete(notification);
}
}