import 'package:comunic/helpers/events_helper.dart'; import 'package:comunic/helpers/notifications_helper.dart'; import 'package:comunic/models/count_unread_notifications.dart'; import 'package:comunic/ui/widgets/safe_state.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:comunic/utils/ui_utils.dart'; import 'package:flutter/material.dart'; /// Navigation bar widget /// /// @author Pierre HUBERT typedef OnSelectMenuAction = void Function(BarCallbackActions); /// Callback actions enum BarCallbackActions { OPEN_CUSTOM_WIDGET, OPEN_NOTIFICATIONS, OPEN_CONVERSATIONS, OPEN_NEWEST_POSTS, OPEN_FRIENDS, OPEN_MY_PAGE, OPEN_SEARCH_PAGE, OPEN_GROUPS, OPEN_GROUP_PAGE, OPEN_USER_PAGE, OPEN_USER_ACCESS_DENIED_PAGE, OPEN_ACCOUNT_SETTINGS, OPEN_APP_SETTINGS, OPEN_USER_FRIENDS_LIST, OPEN_ABOUT_DIALOG, OPEN_CONVERSATION, NONE, ACTION_LOGOUT } Color _primaryColor() => darkTheme() ? Colors.black : Colors.blue; Color _secondaryColor() => darkTheme() ? darkAccentColor : Colors.white; /// Menu item information class _MenuItem { final String label; final Widget icon; final BarCallbackActions action; final bool isMenu; const _MenuItem({ @required this.label, @required this.icon, @required this.action, this.isMenu = false, }) : assert(label != null), assert(icon != null || isMenu), assert(action != null), assert(isMenu != null); } /// 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); } /// 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), action: BarCallbackActions.OPEN_CONVERSATIONS), _MenuItem( label: tr("Newest"), icon: Icon(Icons.refresh), action: BarCallbackActions.OPEN_NEWEST_POSTS), _MenuItem( label: tr("Friends"), icon: Icon(Icons.group), action: BarCallbackActions.OPEN_FRIENDS), _MenuItem( label: tr("Menu"), icon: Icon(Icons.more_vert), isMenu: true, action: BarCallbackActions.NONE) ]; /// List of menu actions items final _menuActionsItem = <_ActionMenuItem>[ _ActionMenuItem( label: tr("My Page"), action: BarCallbackActions.OPEN_MY_PAGE), _ActionMenuItem(label: tr("Groups"), action: BarCallbackActions.OPEN_GROUPS), _ActionMenuItem( label: tr("Search"), action: BarCallbackActions.OPEN_SEARCH_PAGE), _ActionMenuItem( label: tr("Account settings"), action: BarCallbackActions.OPEN_ACCOUNT_SETTINGS), _ActionMenuItem( label: tr("App settings"), action: BarCallbackActions.OPEN_APP_SETTINGS), _ActionMenuItem( label: tr("About Comunic"), action: BarCallbackActions.OPEN_ABOUT_DIALOG), _ActionMenuItem( label: tr("Sign out"), action: BarCallbackActions.ACTION_LOGOUT), ]; /// Public widget class ComunicAppBar extends StatefulWidget implements PreferredSizeWidget { final OnSelectMenuAction onTap; final BarCallbackActions selectedAction; const ComunicAppBar({Key key, @required this.onTap, @required this.selectedAction}) : assert(onTap != null), super(key: key); @override _ComunicAppBarState createState() => _ComunicAppBarState(); @override Size get preferredSize => Size.fromHeight(40); } class _ComunicAppBarState extends SafeState { var _unreadNotifications = CountUnreadNotifications(notifications: 0, conversations: 0); @override void initState() { _refreshCountUnread(); super.initState(); // Listen to notifications number update this.listenChangeState( (d) => _unreadNotifications.notifications = d.newNum); } 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; } } @override Widget build(BuildContext context) { return Material( color: darkTheme() ? Colors.black : Colors.blue, child: Row( crossAxisAlignment: CrossAxisAlignment.stretch, children: List.generate( _menuItems.length, (i) => _MenuItemWidget( item: _menuItems[i], onTap: widget.onTap, isSelected: _menuItems[i].action == widget.selectedAction, newNotice: getNumberUnread(_menuItems[i].action), ), ), ), ); } } /// The [Widget] part of a menu item class _MenuItemWidget extends StatelessWidget { final _MenuItem item; final OnSelectMenuAction onTap; final bool isSelected; /// Notifications notice final int newNotice; const _MenuItemWidget({ Key key, @required this.item, @required this.onTap, @required this.isSelected, this.newNotice = 0, }) : assert(item != null), assert(onTap != null), assert(isSelected != null), super(key: key); @override Widget build(BuildContext context) { assert(debugCheckHasMaterial(context)); return Expanded( child: Material( color: isSelected ? _secondaryColor() : _primaryColor(), child: !item.isMenu ? InkWell( child: _buildIconContainer(), onTap: () => onTap(item.action), ) : _buildContextMenuPopupButton(), ), ); } Widget _buildIconContainer() { return Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ Spacer(flex: 2), IconTheme( data: IconThemeData( color: isSelected ? _primaryColor() : _secondaryColor()), child: item.icon, ), newNotice > 0 ? Spacer() : Container(), newNotice == 0 ? Container() : Material( 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), )), Spacer(flex: 2), ], ); } // Build context menu Widget _buildContextMenuPopupButton() { return PopupMenuButton( child: _buildIconContainer(), itemBuilder: (i) => _menuActionsItem .map((f) => PopupMenuItem( child: Text(f.label), value: f.action, )) .toList(), onSelected: onTap, ); } }