2020-04-18 12:14:54 +00:00
|
|
|
import 'package:comunic/helpers/events_helper.dart';
|
2020-04-17 11:28:01 +00:00
|
|
|
import 'package:comunic/helpers/notifications_helper.dart';
|
|
|
|
import 'package:comunic/models/count_unread_notifications.dart';
|
2020-05-10 16:29:43 +00:00
|
|
|
import 'package:comunic/ui/routes/main_route/main_route.dart';
|
|
|
|
import 'package:comunic/ui/routes/main_route/page_info.dart';
|
2020-04-17 11:28:01 +00:00
|
|
|
import 'package:comunic/ui/widgets/safe_state.dart';
|
2019-07-01 09:51:23 +00:00
|
|
|
import 'package:comunic/utils/intl_utils.dart';
|
2019-11-01 13:17:46 +00:00
|
|
|
import 'package:comunic/utils/ui_utils.dart';
|
2019-07-01 09:51:23 +00:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
/// Navigation bar widget
|
|
|
|
///
|
|
|
|
/// @author Pierre HUBERT
|
|
|
|
|
|
|
|
typedef OnSelectMenuAction = void Function(BarCallbackActions);
|
|
|
|
|
|
|
|
/// Callback actions
|
|
|
|
enum BarCallbackActions {
|
2019-11-01 13:55:28 +00:00
|
|
|
OPEN_NOTIFICATIONS,
|
2019-07-01 09:51:23 +00:00
|
|
|
OPEN_CONVERSATIONS,
|
|
|
|
OPEN_NEWEST_POSTS,
|
|
|
|
OPEN_FRIENDS,
|
2019-07-01 10:06:14 +00:00
|
|
|
OPEN_MY_PAGE,
|
2020-04-17 08:30:29 +00:00
|
|
|
OPEN_SEARCH_PAGE,
|
2020-04-15 10:04:19 +00:00
|
|
|
OPEN_GROUPS,
|
2020-05-12 16:40:07 +00:00
|
|
|
OPEN_SETTINGS,
|
2019-07-01 09:51:23 +00:00
|
|
|
ACTION_LOGOUT
|
|
|
|
}
|
|
|
|
|
2019-11-01 13:17:46 +00:00
|
|
|
Color _primaryColor() => darkTheme() ? Colors.black : Colors.blue;
|
2019-11-01 13:55:28 +00:00
|
|
|
|
2019-11-01 13:17:46 +00:00
|
|
|
Color _secondaryColor() => darkTheme() ? darkAccentColor : Colors.white;
|
2019-07-01 09:51:23 +00:00
|
|
|
|
|
|
|
/// Menu item information
|
|
|
|
class _MenuItem {
|
|
|
|
final String label;
|
|
|
|
final Widget icon;
|
|
|
|
final BarCallbackActions action;
|
|
|
|
final bool isMenu;
|
2020-05-10 16:29:43 +00:00
|
|
|
final PageType pageType;
|
2019-07-01 09:51:23 +00:00
|
|
|
|
2019-11-01 08:59:22 +00:00
|
|
|
const _MenuItem({
|
|
|
|
@required this.label,
|
|
|
|
@required this.icon,
|
|
|
|
@required this.action,
|
2020-05-10 16:29:43 +00:00
|
|
|
@required this.pageType,
|
2019-11-01 08:59:22 +00:00
|
|
|
this.isMenu = false,
|
|
|
|
}) : assert(label != null),
|
2020-05-10 16:29:43 +00:00
|
|
|
assert(isMenu != null),
|
|
|
|
assert(isMenu || icon != null),
|
|
|
|
assert(isMenu || action != null),
|
|
|
|
assert(isMenu || pageType != null);
|
2019-07-01 09:51:23 +00:00
|
|
|
}
|
|
|
|
|
2019-07-01 10:06:14 +00:00
|
|
|
/// Item of action menu
|
|
|
|
class _ActionMenuItem {
|
|
|
|
final String label;
|
|
|
|
final BarCallbackActions action;
|
|
|
|
|
|
|
|
const _ActionMenuItem({@required this.label, @required this.action})
|
|
|
|
: assert(label != null),
|
|
|
|
assert(action != null);
|
|
|
|
}
|
|
|
|
|
2019-07-01 09:51:23 +00:00
|
|
|
/// List of menu items to show
|
|
|
|
final _menuItems = <_MenuItem>[
|
2019-11-01 13:55:28 +00:00
|
|
|
_MenuItem(
|
|
|
|
label: tr("Notifications"),
|
|
|
|
icon: Icon(Icons.notifications),
|
2020-05-10 16:29:43 +00:00
|
|
|
action: BarCallbackActions.OPEN_NOTIFICATIONS,
|
|
|
|
pageType: PageType.NOTIFICATIONS_PAGE),
|
2019-07-01 09:51:23 +00:00
|
|
|
_MenuItem(
|
|
|
|
label: tr("Conversations"),
|
|
|
|
icon: Icon(Icons.comment),
|
2020-05-10 16:29:43 +00:00
|
|
|
action: BarCallbackActions.OPEN_CONVERSATIONS,
|
|
|
|
pageType: PageType.CONVERSATIONS_LIST_PAGE),
|
2019-07-01 09:51:23 +00:00
|
|
|
_MenuItem(
|
|
|
|
label: tr("Newest"),
|
|
|
|
icon: Icon(Icons.refresh),
|
2020-05-10 16:29:43 +00:00
|
|
|
action: BarCallbackActions.OPEN_NEWEST_POSTS,
|
|
|
|
pageType: PageType.LATEST_POSTS_PAGE),
|
2019-07-01 09:51:23 +00:00
|
|
|
_MenuItem(
|
|
|
|
label: tr("Friends"),
|
|
|
|
icon: Icon(Icons.group),
|
2020-05-10 16:29:43 +00:00
|
|
|
action: BarCallbackActions.OPEN_FRIENDS,
|
|
|
|
pageType: PageType.FRIENDS_LIST_PAGE),
|
2019-07-01 09:51:23 +00:00
|
|
|
_MenuItem(
|
|
|
|
label: tr("Menu"),
|
|
|
|
icon: Icon(Icons.more_vert),
|
|
|
|
isMenu: true,
|
2020-05-10 16:29:43 +00:00
|
|
|
action: null,
|
|
|
|
pageType: null)
|
2019-07-01 09:51:23 +00:00
|
|
|
];
|
|
|
|
|
2019-07-01 10:06:14 +00:00
|
|
|
/// List of menu actions items
|
|
|
|
final _menuActionsItem = <_ActionMenuItem>[
|
|
|
|
_ActionMenuItem(
|
|
|
|
label: tr("My Page"), action: BarCallbackActions.OPEN_MY_PAGE),
|
2020-04-15 10:04:19 +00:00
|
|
|
_ActionMenuItem(label: tr("Groups"), action: BarCallbackActions.OPEN_GROUPS),
|
2020-04-17 08:30:29 +00:00
|
|
|
_ActionMenuItem(
|
|
|
|
label: tr("Search"), action: BarCallbackActions.OPEN_SEARCH_PAGE),
|
|
|
|
_ActionMenuItem(
|
2020-05-12 16:40:07 +00:00
|
|
|
label: tr("Settings"), action: BarCallbackActions.OPEN_SETTINGS),
|
2019-07-01 10:06:14 +00:00
|
|
|
_ActionMenuItem(
|
|
|
|
label: tr("Sign out"), action: BarCallbackActions.ACTION_LOGOUT),
|
|
|
|
];
|
|
|
|
|
2019-07-01 09:51:23 +00:00
|
|
|
/// Public widget
|
2020-05-10 16:29:43 +00:00
|
|
|
class ComunicMobileAppBar extends StatefulWidget
|
|
|
|
implements PreferredSizeWidget {
|
|
|
|
final PageInfo currentPage;
|
|
|
|
|
|
|
|
const ComunicMobileAppBar({
|
|
|
|
Key key,
|
|
|
|
@required this.currentPage,
|
|
|
|
}) : assert(currentPage != null),
|
2019-07-01 09:51:23 +00:00
|
|
|
super(key: key);
|
|
|
|
|
2020-04-17 11:28:01 +00:00
|
|
|
@override
|
2020-05-06 16:25:55 +00:00
|
|
|
_ComunicMobileAppBarState createState() => _ComunicMobileAppBarState();
|
2020-04-17 11:28:01 +00:00
|
|
|
|
|
|
|
@override
|
|
|
|
Size get preferredSize => Size.fromHeight(40);
|
|
|
|
}
|
|
|
|
|
2020-05-06 16:25:55 +00:00
|
|
|
class _ComunicMobileAppBarState extends SafeState<ComunicMobileAppBar> {
|
2020-04-18 12:14:54 +00:00
|
|
|
var _unreadNotifications =
|
2020-05-03 15:00:38 +00:00
|
|
|
CountUnreadNotifications(notifications: 0, conversations: 0);
|
2020-04-17 11:28:01 +00:00
|
|
|
|
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
_refreshCountUnread();
|
|
|
|
super.initState();
|
2020-04-18 12:14:54 +00:00
|
|
|
|
|
|
|
// Listen to notifications number update
|
|
|
|
this.listenChangeState<NewNumberNotifsEvent>(
|
2020-05-03 15:00:38 +00:00
|
|
|
(d) => _unreadNotifications.notifications = d.newNum);
|
2020-04-18 12:33:07 +00:00
|
|
|
this.listenChangeState<NewNumberUnreadConversations>(
|
2020-05-03 15:00:38 +00:00
|
|
|
(d) => _unreadNotifications.conversations = d.newNum);
|
2020-04-17 11:28:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void _refreshCountUnread() async {
|
|
|
|
try {
|
|
|
|
final count = await NotificationsHelper().countUnread();
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
_unreadNotifications = count;
|
|
|
|
});
|
|
|
|
} catch (e, stack) {
|
|
|
|
print("Could not refresh the number of unread notifications: $e");
|
|
|
|
print(stack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get the number of unread notifications for the selected notice
|
|
|
|
int getNumberUnread(BarCallbackActions action) {
|
|
|
|
if (_unreadNotifications == null) return 0;
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
case BarCallbackActions.OPEN_NOTIFICATIONS:
|
|
|
|
return _unreadNotifications.notifications;
|
|
|
|
|
|
|
|
case BarCallbackActions.OPEN_CONVERSATIONS:
|
|
|
|
return _unreadNotifications.conversations;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-01 09:51:23 +00:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Material(
|
2019-11-01 13:17:46 +00:00
|
|
|
color: darkTheme() ? Colors.black : Colors.blue,
|
2019-07-01 09:51:23 +00:00
|
|
|
child: Row(
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
|
|
children: List.generate(
|
|
|
|
_menuItems.length,
|
2020-05-03 15:00:38 +00:00
|
|
|
(i) => _MenuItemWidget(
|
2019-11-01 08:59:22 +00:00
|
|
|
item: _menuItems[i],
|
2020-05-10 16:29:43 +00:00
|
|
|
onTap: _handleAction,
|
|
|
|
isSelected: _menuItems[i].pageType == widget.currentPage.type,
|
2020-04-17 11:28:01 +00:00
|
|
|
newNotice: getNumberUnread(_menuItems[i].action),
|
2019-11-01 08:59:22 +00:00
|
|
|
),
|
2019-07-01 09:51:23 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
2020-05-10 16:29:43 +00:00
|
|
|
|
|
|
|
void _handleAction(BarCallbackActions action) {
|
|
|
|
final controller = MainController.of(context);
|
|
|
|
switch (action) {
|
|
|
|
case BarCallbackActions.OPEN_NOTIFICATIONS:
|
|
|
|
controller.openNotificationsPage();
|
|
|
|
break;
|
|
|
|
case BarCallbackActions.OPEN_CONVERSATIONS:
|
|
|
|
controller.openConversationsPage();
|
|
|
|
break;
|
|
|
|
case BarCallbackActions.OPEN_NEWEST_POSTS:
|
|
|
|
controller.openLatestPostsPage();
|
|
|
|
break;
|
|
|
|
case BarCallbackActions.OPEN_FRIENDS:
|
|
|
|
controller.openFriendsList();
|
|
|
|
break;
|
|
|
|
case BarCallbackActions.OPEN_MY_PAGE:
|
|
|
|
controller.openCurrentUserPage();
|
|
|
|
break;
|
|
|
|
case BarCallbackActions.OPEN_SEARCH_PAGE:
|
|
|
|
controller.openSearchPage();
|
|
|
|
break;
|
|
|
|
case BarCallbackActions.OPEN_GROUPS:
|
|
|
|
controller.openGroupsListPage();
|
|
|
|
break;
|
2020-05-12 16:40:07 +00:00
|
|
|
case BarCallbackActions.OPEN_SETTINGS:
|
|
|
|
controller.openSettings();
|
2020-05-10 16:29:43 +00:00
|
|
|
break;
|
|
|
|
case BarCallbackActions.ACTION_LOGOUT:
|
|
|
|
controller.requestLogout();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-07-01 09:51:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// The [Widget] part of a menu item
|
|
|
|
class _MenuItemWidget extends StatelessWidget {
|
|
|
|
final _MenuItem item;
|
|
|
|
final OnSelectMenuAction onTap;
|
|
|
|
final bool isSelected;
|
|
|
|
|
2020-04-17 11:29:00 +00:00
|
|
|
/// Notifications notice
|
2020-04-17 11:28:01 +00:00
|
|
|
final int newNotice;
|
|
|
|
|
|
|
|
const _MenuItemWidget({
|
|
|
|
Key key,
|
|
|
|
@required this.item,
|
|
|
|
@required this.onTap,
|
|
|
|
@required this.isSelected,
|
|
|
|
this.newNotice = 0,
|
|
|
|
}) : assert(item != null),
|
2019-07-01 09:51:23 +00:00
|
|
|
assert(onTap != null),
|
|
|
|
assert(isSelected != null),
|
|
|
|
super(key: key);
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
assert(debugCheckHasMaterial(context));
|
|
|
|
|
|
|
|
return Expanded(
|
|
|
|
child: Material(
|
2019-11-01 13:17:46 +00:00
|
|
|
color: isSelected ? _secondaryColor() : _primaryColor(),
|
2019-07-01 09:51:23 +00:00
|
|
|
child: !item.isMenu
|
|
|
|
? InkWell(
|
2020-05-03 15:00:38 +00:00
|
|
|
child: _buildIconContainer(),
|
|
|
|
onTap: () => onTap(item.action),
|
|
|
|
)
|
2019-07-01 09:51:23 +00:00
|
|
|
: _buildContextMenuPopupButton(),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget _buildIconContainer() {
|
2020-04-17 11:28:01 +00:00
|
|
|
return Row(
|
2019-07-01 09:51:23 +00:00
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
2020-04-17 11:28:01 +00:00
|
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
2019-07-01 09:51:23 +00:00
|
|
|
children: <Widget>[
|
2020-04-17 11:29:00 +00:00
|
|
|
Spacer(flex: 2),
|
2019-07-01 09:51:23 +00:00
|
|
|
IconTheme(
|
|
|
|
data: IconThemeData(
|
2019-11-01 13:17:46 +00:00
|
|
|
color: isSelected ? _primaryColor() : _secondaryColor()),
|
2019-07-01 09:51:23 +00:00
|
|
|
child: item.icon,
|
2020-04-17 11:28:01 +00:00
|
|
|
),
|
|
|
|
newNotice > 0 ? Spacer() : Container(),
|
|
|
|
newNotice == 0
|
|
|
|
? Container()
|
|
|
|
: Material(
|
2020-05-03 15:00:38 +00:00
|
|
|
color: Colors.red,
|
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.all(2.0),
|
|
|
|
child: Text(" $newNotice ",
|
|
|
|
style: TextStyle(color: Colors.white)),
|
|
|
|
),
|
|
|
|
borderRadius: BorderRadius.all(
|
|
|
|
Radius.circular(50.0),
|
|
|
|
)),
|
2020-04-17 11:29:00 +00:00
|
|
|
Spacer(flex: 2),
|
2019-07-01 09:51:23 +00:00
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build context menu
|
|
|
|
Widget _buildContextMenuPopupButton() {
|
|
|
|
return PopupMenuButton<BarCallbackActions>(
|
|
|
|
child: _buildIconContainer(),
|
2019-07-01 10:06:14 +00:00
|
|
|
itemBuilder: (i) => _menuActionsItem
|
|
|
|
.map((f) => PopupMenuItem(
|
2020-05-03 15:00:38 +00:00
|
|
|
child: Text(f.label),
|
|
|
|
value: f.action,
|
|
|
|
))
|
2019-07-01 10:06:14 +00:00
|
|
|
.toList(),
|
2019-07-01 09:51:23 +00:00
|
|
|
onSelected: onTap,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|