mirror of
				https://gitlab.com/comunic/comunicmobile
				synced 2025-11-04 04:04:18 +00:00 
			
		
		
		
	ComunicAppBar => ComunicMobileAppBar
This commit is contained in:
		
							
								
								
									
										270
									
								
								lib/ui/widgets/mobile_mode/mobile_navbar_widget.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								lib/ui/widgets/mobile_mode/mobile_navbar_widget.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,270 @@
 | 
			
		||||
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_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("Sign out"), action: BarCallbackActions.ACTION_LOGOUT),
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/// Public widget
 | 
			
		||||
class ComunicMobileAppBar extends StatefulWidget implements PreferredSizeWidget {
 | 
			
		||||
  final OnSelectMenuAction onTap;
 | 
			
		||||
  final BarCallbackActions selectedAction;
 | 
			
		||||
 | 
			
		||||
  const ComunicMobileAppBar(
 | 
			
		||||
      {Key key, @required this.onTap, @required this.selectedAction})
 | 
			
		||||
      : assert(onTap != null),
 | 
			
		||||
        super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  _ComunicMobileAppBarState createState() => _ComunicMobileAppBarState();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Size get preferredSize => Size.fromHeight(40);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _ComunicMobileAppBarState extends SafeState<ComunicMobileAppBar> {
 | 
			
		||||
  var _unreadNotifications =
 | 
			
		||||
      CountUnreadNotifications(notifications: 0, conversations: 0);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
    _refreshCountUnread();
 | 
			
		||||
    super.initState();
 | 
			
		||||
 | 
			
		||||
    // Listen to notifications number update
 | 
			
		||||
    this.listenChangeState<NewNumberNotifsEvent>(
 | 
			
		||||
        (d) => _unreadNotifications.notifications = d.newNum);
 | 
			
		||||
    this.listenChangeState<NewNumberUnreadConversations>(
 | 
			
		||||
        (d) => _unreadNotifications.conversations = 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: <Widget>[
 | 
			
		||||
        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<BarCallbackActions>(
 | 
			
		||||
      child: _buildIconContainer(),
 | 
			
		||||
      itemBuilder: (i) => _menuActionsItem
 | 
			
		||||
          .map((f) => PopupMenuItem(
 | 
			
		||||
                child: Text(f.label),
 | 
			
		||||
                value: f.action,
 | 
			
		||||
              ))
 | 
			
		||||
          .toList(),
 | 
			
		||||
      onSelected: onTap,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user