From 61124c34ef44bc1f569daf83b798f10528ff3eb2 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Fri, 1 Nov 2019 14:55:28 +0100 Subject: [PATCH] Ready to implement the list of notifications --- lib/helpers/notifications_helper.dart | 78 ++++++++++++++++++++++++ lib/lists/abstract_list.dart | 19 ++++++ lib/lists/notifications_list.dart | 8 +++ lib/models/notification.dart | 69 +++++++++++++++++++++ lib/ui/routes/home_route.dart | 4 ++ lib/ui/screens/notifications_screen.dart | 46 ++++++++++++++ lib/ui/widgets/navbar_widget.dart | 6 ++ 7 files changed, 230 insertions(+) create mode 100644 lib/helpers/notifications_helper.dart create mode 100644 lib/lists/abstract_list.dart create mode 100644 lib/lists/notifications_list.dart create mode 100644 lib/models/notification.dart create mode 100644 lib/ui/screens/notifications_screen.dart diff --git a/lib/helpers/notifications_helper.dart b/lib/helpers/notifications_helper.dart new file mode 100644 index 0000000..3b2adcc --- /dev/null +++ b/lib/helpers/notifications_helper.dart @@ -0,0 +1,78 @@ +import 'package:comunic/lists/notifications_list.dart'; +import 'package:comunic/models/api_request.dart'; +import 'package:comunic/models/notification.dart'; + +/// Notifications helper +/// +/// @author Pierre HUBERT + +const _NotificationElementTypeAPImapping = { + "user_page": NotificationElementType.USER_PAGE, + "group_page": NotificationElementType.GROUP_PAGE, + "conversation": NotificationElementType.CONVERSATION, + "conversation_message": NotificationElementType.CONVERSATION_MESSAGE, + "post": NotificationElementType.POST, + "post_text": NotificationElementType.POST_TEXT, + "post_img": NotificationElementType.POST_IMAGE, + "post_youtube": NotificationElementType.POST_YOUTUBE, + "post_movie": NotificationElementType.POST_MOVIE, + "post_weblink": NotificationElementType.POST_WEBLINK, + "post_pdf": NotificationElementType.POST_PDF, + "post_timer": NotificationElementType.POST_TIMER, + "post_survey": NotificationElementType.POST_SURVEY, + "comment": NotificationElementType.COMMENT, + "friend_request": NotificationElementType.FRIENDSHIP_REQUEST, + "group_membership": NotificationElementType.GROUP_MEMBERSHIP, +}; + +const _NotificationsTypeAPImapping = { + "comment_created": NotificationType.COMMENT_CREATED, + "sent_friend_request": NotificationType.SENT_FRIEND_REQUEST, + "accepted_friend_request": NotificationType.ACCEPTED_FRIEND_REQUEST, + "rejected_friend_request": NotificationType.REJECTED_FRIEND_REQUEST, + "elem_created": NotificationType.ELEM_CREATED, + "elem_updated": NotificationType.ELEM_UPDATED, + "sent_group_membership_invitation": + NotificationType.SENT_GROUP_MEMBERSHIP_INVITATION, + "accepted_group_membership_invitation": + NotificationType.ACCEPTED_GROUP_MEMBERSHIP_INVITATION, + "rejected_group_membership_invitation": + NotificationType.REJECTED_GROUP_MEMBERSHIP_INVITATION, + "sent_group_membership_request": + NotificationType.SENT_GROUP_MEMBERSHIP_REQUEST, + "accepted_group_membership_request": + NotificationType.ACCEPTED_GROUP_MEMBERSHIP_REQUEST, + "rejected_group_membership_request": + NotificationType.REJECTED_GROUP_MEMBERSHIP_REQUEST, +}; + +class NotificationsHelper { + /// Get the list of unread notifications of the user + Future getUnread() async { + final response = + await APIRequest(uri: "notifications/get_list_unread", needLogin: true) + .exec(); + + if (!response.isOK) + throw Exception("Could not get the list of notifications!"); + + // Parse the list of notifications + return NotificationsList() + ..addAll(response + .getArray() + .map((f) => Notification( + id: f["id"], + timeCreate: f["time_create"], + seen: f["seen"], + fromUser: f["from_user_id"], + onElemId: f["on_elem_id"], + onElemType: _NotificationElementTypeAPImapping[f["on_elem_type"]], + type: _NotificationsTypeAPImapping[f["type"]], + fromContainerId: f["from_container_id"], + fromContainerType: f["from_container_type"] == "" + ? null + : _NotificationElementTypeAPImapping[ + f["from_container_type"]])) + .toList()); + } +} diff --git a/lib/lists/abstract_list.dart b/lib/lists/abstract_list.dart new file mode 100644 index 0000000..54a00e5 --- /dev/null +++ b/lib/lists/abstract_list.dart @@ -0,0 +1,19 @@ +import 'dart:collection'; + +/// Abstract list +/// +/// @author Pierre HUBERT + +class AbstractList extends ListBase { + final _list = List(); + + int get length => _list.length; + + set length(int l) => _list.length = l; + + @override + E operator [](int index) => _list[index]; + + @override + void operator []=(int index, E value) => _list[index] = value; +} diff --git a/lib/lists/notifications_list.dart b/lib/lists/notifications_list.dart new file mode 100644 index 0000000..f0d4ff1 --- /dev/null +++ b/lib/lists/notifications_list.dart @@ -0,0 +1,8 @@ +import 'package:comunic/lists/abstract_list.dart'; +import 'package:comunic/models/notification.dart'; + +/// Notifications list +/// +/// @author Pierre HUBERT + +class NotificationsList extends AbstractList {} diff --git a/lib/models/notification.dart b/lib/models/notification.dart new file mode 100644 index 0000000..51cdc1b --- /dev/null +++ b/lib/models/notification.dart @@ -0,0 +1,69 @@ +import 'package:flutter/widgets.dart'; + +/// Notification model +/// +/// @author Pierre HUBERT + +enum NotificationElementType { + USER_PAGE, + GROUP_PAGE, + CONVERSATION, + CONVERSATION_MESSAGE, + POST, + POST_TEXT, + POST_IMAGE, + POST_YOUTUBE, + POST_MOVIE, + POST_WEBLINK, + POST_PDF, + POST_TIMER, + POST_SURVEY, + COMMENT, + FRIENDSHIP_REQUEST, + GROUP_MEMBERSHIP, +} + +enum NotificationType { + COMMENT_CREATED, + SENT_FRIEND_REQUEST, + ACCEPTED_FRIEND_REQUEST, + REJECTED_FRIEND_REQUEST, + ELEM_CREATED, + ELEM_UPDATED, + SENT_GROUP_MEMBERSHIP_INVITATION, + ACCEPTED_GROUP_MEMBERSHIP_INVITATION, + REJECTED_GROUP_MEMBERSHIP_INVITATION, + SENT_GROUP_MEMBERSHIP_REQUEST, + ACCEPTED_GROUP_MEMBERSHIP_REQUEST, + REJECTED_GROUP_MEMBERSHIP_REQUEST, +} + +class Notification { + final int id; + final int timeCreate; + final bool seen; + final int fromUser; + final int onElemId; + final NotificationElementType onElemType; + final NotificationType type; + final int fromContainerId; + final NotificationElementType fromContainerType; + + const Notification({ + @required this.id, + @required this.timeCreate, + @required this.seen, + @required this.fromUser, + @required this.onElemId, + @required this.onElemType, + @required this.type, + @required this.fromContainerId, + @required this.fromContainerType, + }) : assert(id != null), + assert(timeCreate != null), + assert(seen != null), + assert(fromUser != null), + assert(onElemId != null), + assert(onElemType != null), + assert(type != null); +} diff --git a/lib/ui/routes/home_route.dart b/lib/ui/routes/home_route.dart index 1801670..cf9da6b 100644 --- a/lib/ui/routes/home_route.dart +++ b/lib/ui/routes/home_route.dart @@ -3,6 +3,7 @@ import 'package:comunic/ui/routes/app_settings_route.dart'; import 'package:comunic/ui/screens/conversations_list_screen.dart'; import 'package:comunic/ui/screens/friends_list_screen.dart'; import 'package:comunic/ui/screens/newest_posts.dart'; +import 'package:comunic/ui/screens/notifications_screen.dart'; import 'package:comunic/ui/widgets/navbar_widget.dart'; import 'package:comunic/utils/account_utils.dart'; import 'package:comunic/utils/intl_utils.dart'; @@ -76,6 +77,9 @@ class _HomeRouteState extends State { /// Build the body of the application Widget _buildBody(BuildContext context) { switch (_currTab) { + case BarCallbackActions.OPEN_NOTIFICATIONS: + return NotificationsScreen(); + case BarCallbackActions.OPEN_CONVERSATIONS: return ConversationsListScreen(); diff --git a/lib/ui/screens/notifications_screen.dart b/lib/ui/screens/notifications_screen.dart new file mode 100644 index 0000000..40386c0 --- /dev/null +++ b/lib/ui/screens/notifications_screen.dart @@ -0,0 +1,46 @@ +import 'package:comunic/lists/notifications_list.dart'; +import 'package:comunic/utils/intl_utils.dart'; +import 'package:comunic/utils/ui_utils.dart'; +import 'package:flutter/material.dart'; + +/// Notifications screen +/// +/// @author Pierre HUBERT + +enum _Status { LOADING, ERROR, NONE } + +class NotificationsScreen extends StatefulWidget { + @override + _NotificationsScreenState createState() => _NotificationsScreenState(); +} + +class _NotificationsScreenState extends State { + NotificationsList _list; + _Status _status = _Status.LOADING; + + void setStatus(_Status s) => setState(() => _status = s); + + Future _loadList() async { + setStatus(_Status.LOADING); + + } + + @override + Widget build(BuildContext context) { + // 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())), + ) + ]); + + // Loading status + if (_list == null || _status == _Status.LOADING) + return Center( + child: CircularProgressIndicator(), + ); + } +} diff --git a/lib/ui/widgets/navbar_widget.dart b/lib/ui/widgets/navbar_widget.dart index 88d8219..27f555b 100644 --- a/lib/ui/widgets/navbar_widget.dart +++ b/lib/ui/widgets/navbar_widget.dart @@ -10,6 +10,7 @@ typedef OnSelectMenuAction = void Function(BarCallbackActions); /// Callback actions enum BarCallbackActions { + OPEN_NOTIFICATIONS, OPEN_CONVERSATIONS, OPEN_NEWEST_POSTS, OPEN_FRIENDS, @@ -20,6 +21,7 @@ enum BarCallbackActions { } Color _primaryColor() => darkTheme() ? Colors.black : Colors.blue; + Color _secondaryColor() => darkTheme() ? darkAccentColor : Colors.white; /// Menu item information @@ -52,6 +54,10 @@ class _ActionMenuItem { /// List of menu items to show final _menuItems = <_MenuItem>[ + _MenuItem( + label: tr("Notifications"), + icon: Icon(Icons.notifications), + action: BarCallbackActions.OPEN_NOTIFICATIONS), _MenuItem( label: tr("Conversations"), icon: Icon(Icons.comment),