2019-11-01 14:37:27 +00:00
|
|
|
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';
|
2019-11-01 13:55:28 +00:00
|
|
|
import 'package:comunic/lists/notifications_list.dart';
|
2019-11-01 14:37:27 +00:00
|
|
|
import 'package:comunic/lists/users_list.dart';
|
2019-11-02 08:57:22 +00:00
|
|
|
import 'package:comunic/models/notification.dart' as n;
|
2020-04-17 13:26:37 +00:00
|
|
|
import 'package:comunic/ui/routes/main_route.dart';
|
2019-11-02 08:43:09 +00:00
|
|
|
import 'package:comunic/ui/widgets/account_image_widget.dart';
|
2019-11-02 08:57:22 +00:00
|
|
|
import 'package:comunic/utils/date_utils.dart';
|
2019-11-01 13:55:28 +00:00
|
|
|
import 'package:comunic/utils/intl_utils.dart';
|
2019-11-02 11:46:17 +00:00
|
|
|
import 'package:comunic/utils/navigation_utils.dart';
|
2019-11-01 13:55:28 +00:00
|
|
|
import 'package:comunic/utils/ui_utils.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
/// Notifications screen
|
|
|
|
///
|
|
|
|
/// @author Pierre HUBERT
|
|
|
|
|
|
|
|
enum _Status { LOADING, ERROR, NONE }
|
|
|
|
|
2019-11-02 11:14:17 +00:00
|
|
|
enum _PopupMenuActions { DELETE }
|
|
|
|
|
2019-11-01 13:55:28 +00:00
|
|
|
class NotificationsScreen extends StatefulWidget {
|
|
|
|
@override
|
|
|
|
_NotificationsScreenState createState() => _NotificationsScreenState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _NotificationsScreenState extends State<NotificationsScreen> {
|
|
|
|
NotificationsList _list;
|
2019-11-01 14:37:27 +00:00
|
|
|
UsersList _users;
|
|
|
|
GroupsList _groups;
|
2019-11-01 13:55:28 +00:00
|
|
|
_Status _status = _Status.LOADING;
|
|
|
|
|
2020-04-17 11:50:47 +00:00
|
|
|
final _refreshKey = GlobalKey<RefreshIndicatorState>();
|
|
|
|
|
2019-11-01 13:55:28 +00:00
|
|
|
void setStatus(_Status s) => setState(() => _status = s);
|
|
|
|
|
|
|
|
Future<void> _loadList() async {
|
|
|
|
setStatus(_Status.LOADING);
|
|
|
|
|
2019-11-01 14:37:27 +00:00
|
|
|
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;
|
|
|
|
});
|
2019-11-01 14:48:02 +00:00
|
|
|
|
|
|
|
setStatus(_Status.NONE);
|
2019-11-01 14:37:27 +00:00
|
|
|
} on Exception catch (e) {
|
|
|
|
print("Exception while getting the list of notifications!");
|
|
|
|
print(e);
|
|
|
|
} on Error catch (e) {
|
|
|
|
print("Error while getting the list of notifications!");
|
|
|
|
print(e.stackTrace);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void didChangeDependencies() {
|
|
|
|
super.didChangeDependencies();
|
|
|
|
_loadList();
|
2019-11-01 13:55:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2019-11-01 14:48:02 +00:00
|
|
|
// Loading status
|
|
|
|
if (_list == null || _status == _Status.LOADING)
|
|
|
|
return Center(
|
|
|
|
child: CircularProgressIndicator(),
|
|
|
|
);
|
|
|
|
|
2020-04-17 12:06:01 +00:00
|
|
|
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: 20.0,
|
|
|
|
bottom: 20.0,
|
|
|
|
child: FloatingActionButton(
|
|
|
|
onPressed: () => _deleteAllNotifications(),
|
|
|
|
child: Icon(Icons.delete),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
]),
|
2019-11-01 14:48:02 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Build body
|
|
|
|
Widget _buildBody() {
|
2019-11-02 08:43:09 +00:00
|
|
|
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,
|
2019-11-02 11:14:17 +00:00
|
|
|
onDelete: _deleteNotification,
|
2019-11-02 08:43:09 +00:00
|
|
|
))
|
|
|
|
.toList(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildSingleChildCases() {
|
2019-11-01 13:55:28 +00:00
|
|
|
// 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())),
|
|
|
|
)
|
|
|
|
]);
|
|
|
|
|
2019-11-01 14:48:02 +00:00
|
|
|
// 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.")),
|
|
|
|
),
|
2019-11-01 13:55:28 +00:00
|
|
|
);
|
2019-11-02 12:46:05 +00:00
|
|
|
|
|
|
|
throw Error();
|
2019-11-01 13:55:28 +00:00
|
|
|
}
|
2019-11-02 11:14:17 +00:00
|
|
|
|
|
|
|
/// Delete a notification
|
|
|
|
void _deleteNotification(n.Notification notif) async {
|
|
|
|
setState(() {
|
|
|
|
_list.remove(notif);
|
|
|
|
});
|
|
|
|
|
|
|
|
NotificationsHelper().markSeen(notif);
|
|
|
|
}
|
2020-04-17 11:50:47 +00:00
|
|
|
|
|
|
|
/// 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();
|
|
|
|
}
|
2019-11-01 13:55:28 +00:00
|
|
|
}
|
2019-11-02 08:43:09 +00:00
|
|
|
|
|
|
|
class _NotificationTile extends StatelessWidget {
|
|
|
|
final n.Notification notification;
|
|
|
|
final UsersList usersList;
|
|
|
|
final GroupsList groupsList;
|
2019-11-02 11:14:17 +00:00
|
|
|
final void Function(n.Notification) onDelete;
|
2019-11-02 08:43:09 +00:00
|
|
|
|
|
|
|
const _NotificationTile({
|
|
|
|
Key key,
|
|
|
|
@required this.notification,
|
|
|
|
@required this.usersList,
|
|
|
|
@required this.groupsList,
|
2019-11-02 11:14:17 +00:00
|
|
|
@required this.onDelete,
|
2019-11-02 08:43:09 +00:00
|
|
|
}) : assert(notification != null),
|
2019-11-02 11:14:17 +00:00
|
|
|
assert(usersList != null),
|
|
|
|
assert(groupsList != null),
|
|
|
|
assert(onDelete != null),
|
2019-11-02 08:43:09 +00:00
|
|
|
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 ListTile(
|
|
|
|
leading: AccountImageWidget(
|
|
|
|
user: srcUser,
|
|
|
|
),
|
2019-11-02 11:46:17 +00:00
|
|
|
onTap: () => _onTap(context),
|
2019-11-02 08:43:09 +00:00
|
|
|
title: Text(message),
|
2019-11-02 08:57:22 +00:00
|
|
|
subtitle: Text(diffTimeFromNowToStr(notification.timeCreate)),
|
2019-11-02 11:14:17 +00:00
|
|
|
trailing: PopupMenuButton<_PopupMenuActions>(
|
|
|
|
onSelected: _popupMenuAction,
|
|
|
|
itemBuilder: (c) => [
|
|
|
|
PopupMenuItem(
|
|
|
|
child: Text(tr("Delete")),
|
|
|
|
value: _PopupMenuActions.DELETE,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
2019-11-02 08:43:09 +00:00
|
|
|
);
|
|
|
|
}
|
2019-11-02 11:14:17 +00:00
|
|
|
|
|
|
|
void _popupMenuAction(_PopupMenuActions value) {
|
|
|
|
switch (value) {
|
|
|
|
case _PopupMenuActions.DELETE:
|
|
|
|
onDelete(notification);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-11-02 11:46:17 +00:00
|
|
|
|
|
|
|
void _onTap(BuildContext context) {
|
|
|
|
if (notification.onElemType == n.NotificationElementType.POST) {
|
|
|
|
openPostFullScreen(notification.onElemId, context);
|
2019-11-02 11:54:18 +00:00
|
|
|
} else if (notification.onElemType ==
|
|
|
|
n.NotificationElementType.FRIENDSHIP_REQUEST) {
|
|
|
|
openUserPage(userID: notification.fromUser, context: context);
|
2020-04-16 14:04:15 +00:00
|
|
|
} else if (notification.onElemType ==
|
|
|
|
n.NotificationElementType.GROUP_MEMBERSHIP) {
|
2020-04-17 13:26:37 +00:00
|
|
|
MainController.of(context).openGroup(notification.onElemId);
|
2019-11-02 12:46:05 +00:00
|
|
|
} else {
|
|
|
|
showSimpleSnack(context,
|
|
|
|
tr("This kind of notification is not supported yet by this application."));
|
|
|
|
return;
|
2019-11-02 11:46:17 +00:00
|
|
|
}
|
|
|
|
|
2019-11-02 12:46:05 +00:00
|
|
|
onDelete(notification);
|
2019-11-02 11:46:17 +00:00
|
|
|
}
|
2019-11-02 08:43:09 +00:00
|
|
|
}
|