1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-30 08:46:27 +00:00
comunicmobile/lib/ui/screens/notifications_screen.dart

341 lines
9.7 KiB
Dart
Raw Normal View History

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';
2019-11-02 08:57:22 +00:00
import 'package:comunic/models/notification.dart' as n;
2020-05-05 11:21:37 +00:00
import 'package:comunic/ui/routes/main_route/main_route.dart';
2019-11-02 08:43:09 +00:00
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';
2019-11-02 08:57:22 +00:00
import 'package:comunic/utils/date_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
2019-11-02 11:46:17 +00:00
import 'package:comunic/utils/navigation_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
/// Notifications screen
///
/// @author Pierre HUBERT
enum _Status { LOADING, ERROR, NONE }
enum _PopupMenuActions { DELETE }
class NotificationsScreen extends StatefulWidget {
2020-05-07 17:13:22 +00:00
final bool useSmallDeleteButton;
const NotificationsScreen({
Key key,
this.useSmallDeleteButton = false,
}) : assert(useSmallDeleteButton != null),
super(key: key);
@override
_NotificationsScreenState createState() => _NotificationsScreenState();
}
class _NotificationsScreenState extends SafeState<NotificationsScreen> {
NotificationsList _list;
UsersList _users;
GroupsList _groups;
_Status _status = _Status.LOADING;
2020-04-17 11:50:47 +00:00
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) {
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 initState() {
super.initState();
2020-04-18 12:20:07 +00:00
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(),
);
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(
2020-05-07 17:13:22 +00:00
right: widget.useSmallDeleteButton ? 0.0 : 20.0,
bottom: widget.useSmallDeleteButton ? 0.0 : 20.0,
2020-04-17 12:06:01 +00:00
child: FloatingActionButton(
2020-05-07 17:13:22 +00:00
mini: widget.useSmallDeleteButton,
2020-04-17 12:06:01 +00:00
onPressed: () => _deleteAllNotifications(),
child: Icon(Icons.delete),
),
2020-05-07 17:13:22 +00:00
)
2020-04-17 12:06:01 +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(
2020-05-05 11:21:37 +00:00
notification: f,
usersList: _users,
groupsList: _groups,
onDelete: _deleteNotification,
))
2019-11-02 08:43:09 +00:00
.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);
}
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-02 08:43:09 +00:00
class _NotificationTile extends StatelessWidget {
final n.Notification notification;
final UsersList usersList;
final GroupsList groupsList;
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,
@required this.onDelete,
2019-11-02 08:43:09 +00:00
}) : assert(notification != null),
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) {
2020-05-05 11:21:37 +00:00
// Comment
2019-11-02 08:43:09 +00:00
case n.NotificationType.COMMENT_CREATED:
message += tr("posted a comment");
break;
2020-05-05 11:21:37 +00:00
// Friendship requests
2019-11-02 08:43:09 +00:00
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;
2020-05-05 11:21:37 +00:00
// Groups membership
2019-11-02 08:43:09 +00:00
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;
2020-05-05 11:21:37 +00:00
// Generic element creation
2019-11-02 08:43:09 +00:00
case n.NotificationType.ELEM_CREATED:
if (notification.onElemType == n.NotificationElementType.POST)
message += tr("created a new post");
break;
case n.NotificationType.ELEM_UPDATED:
2020-05-05 11:21:37 +00:00
// Operation not implemented
2019-11-02 08:43:09 +00:00
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(
2019-11-02 08:43:09 +00:00
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)),
2020-05-07 17:04:58 +00:00
onLongPressOpenMenu: (position) {
showMenu(context: context, position: position, items: [
PopupMenuItem(
child: Text(tr("Delete")),
value: _PopupMenuActions.DELETE,
),
]).then(_popupMenuAction);
},
2019-11-02 08:43:09 +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);
} 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);
} else {
showSimpleSnack(context,
tr("This kind of notification is not supported yet by this application."));
return;
2019-11-02 11:46:17 +00:00
}
onDelete(notification);
2019-11-02 11:46:17 +00:00
}
2019-11-02 08:43:09 +00:00
}