From 229491cd79f44ee859c5a7d1038a92517f882a58 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Sat, 24 Apr 2021 09:46:53 +0200 Subject: [PATCH] Start to build Forez main route --- lib/forez/main_forez_dev.dart | 2 +- lib/forez/ui/routes/forez_route.dart | 111 +++++++++++++++++++++- lib/models/config.dart | 2 +- lib/ui/widgets/init_widget.dart | 2 +- lib/ui/widgets/status_widget.dart | 62 ++++++++++++ lib/ui/widgets/tab_transition_widget.dart | 32 +++++++ 6 files changed, 203 insertions(+), 8 deletions(-) create mode 100644 lib/ui/widgets/status_widget.dart create mode 100644 lib/ui/widgets/tab_transition_widget.dart diff --git a/lib/forez/main_forez_dev.dart b/lib/forez/main_forez_dev.dart index f277c81..3c1535a 100644 --- a/lib/forez/main_forez_dev.dart +++ b/lib/forez/main_forez_dev.dart @@ -34,7 +34,7 @@ void main() { appName: "#Forez", appQuickDescription: tr("Events organisation in Forez plain"), toursEntriesBuilder: buildTour, - mainRouteBuilder: (c) => ForezRoute(), + mainRouteBuilder: (c, k) => ForezRoute(key: k), )); HttpOverrides.global = new MyHttpOverride(); diff --git a/lib/forez/ui/routes/forez_route.dart b/lib/forez/ui/routes/forez_route.dart index 7ca8df0..c22cbba 100644 --- a/lib/forez/ui/routes/forez_route.dart +++ b/lib/forez/ui/routes/forez_route.dart @@ -2,6 +2,10 @@ import 'package:comunic/models/conversation.dart'; import 'package:comunic/ui/dialogs/alert_dialog.dart'; import 'package:comunic/ui/routes/main_route/main_route.dart'; import 'package:comunic/ui/routes/main_route/page_info.dart'; +import 'package:comunic/ui/screens/conversations_list_screen.dart'; +import 'package:comunic/ui/widgets/safe_state.dart'; +import 'package:comunic/ui/widgets/status_widget.dart'; +import 'package:comunic/ui/widgets/tab_transition_widget.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:flutter/material.dart'; @@ -24,9 +28,8 @@ class _MainRouteState extends MainController { @override Widget build(BuildContext context) { - return Container( - color: Colors.blueAccent, - child: SafeArea( + return StatusWidget( + child: (c) => SafeArea( // Avoid OS areas child: WillPopScope( onWillPop: willPop, @@ -52,14 +55,112 @@ class _MainRouteState extends MainController { } } +enum _PopupMenuItems { ACTION_SETTINGS, ACTION_SIGN_OUT } + class ForezRouteBody extends StatefulWidget { @override _ForezRouteBodyState createState() => _ForezRouteBodyState(); } -class _ForezRouteBodyState extends State { +class _ForezRouteBodyState extends SafeState { + @override + void initState() { + super.initState(); + } + @override Widget build(BuildContext context) { - return Text("yolo"); + return DefaultTabController( + length: _tabs.length, + child: Scaffold( + appBar: AppBar( + title: Text("#Forez"), + actions: [_buildPopupMenuButton()], + bottom: TabBar(tabs: _tabs), + ), + body: TabBarView(children: _tabsPages), + ), + ); } + + Widget _buildPopupMenuButton() => PopupMenuButton<_PopupMenuItems>( + itemBuilder: (c) => [ + PopupMenuItem( + child: Text(tr("Settings")), + value: _PopupMenuItems.ACTION_SETTINGS, + ), + PopupMenuItem( + child: Text(tr("Sign out")), + value: _PopupMenuItems.ACTION_SIGN_OUT, + ), + ], + onSelected: _onMenuSelection, + ); + + void _onMenuSelection(_PopupMenuItems value) { + switch (value) { + case _PopupMenuItems.ACTION_SETTINGS: + MainController.of(context).openSettings(); + break; + case _PopupMenuItems.ACTION_SIGN_OUT: + // TODO : handle logout + break; + } + } + + final _list = <_Tab>[ + // Presence tab + _Tab( + icon: Icons.calendar_today, + title: tr("Presence"), + widget: Text("Presence"), + ), + + // Conversations tab + _Tab( + icon: Icons.question_answer, + title: tr("Conversations"), + widget: ConversationsListScreen(), + isUnread: (c) => StatusWidgetState.of(c).unreadConversations > 0, + ), + + // Directory tab + _Tab( + icon: Icons.import_contacts, + title: tr("Directory"), + widget: Text("Directory"), + ), + ]; + + List get _tabs => _list + .map((e) => Tab( + icon: Stack( + children: [ + Icon(e.icon), + e.isUnread?.call(context) ?? false + ? Container(color: Colors.red, width: 10, height: 10) + : Container(width: 0) + ], + ), + text: e.title)) + .toList(); + + List get _tabsPages => + _list.map((e) => TabTransitionWidget(e.widget)).toList(); +} + +class _Tab { + final IconData icon; + final String title; + final Widget widget; + final bool Function(BuildContext) isUnread; + + const _Tab({ + @required this.icon, + @required this.title, + @required this.widget, + this.isUnread, + }) : assert(icon != null), + assert(title != null), + assert(widget != null); } diff --git a/lib/models/config.dart b/lib/models/config.dart index 32a8917..e9cde97 100644 --- a/lib/models/config.dart +++ b/lib/models/config.dart @@ -28,7 +28,7 @@ class Config { final TourEntriesBuilder toursEntriesBuilder; // Custom main application route - final Widget Function(BuildContext) mainRouteBuilder; + final Widget Function(BuildContext, GlobalKey) mainRouteBuilder; const Config({ @required this.apiServerName, diff --git a/lib/ui/widgets/init_widget.dart b/lib/ui/widgets/init_widget.dart index bbcd5b0..d66c868 100644 --- a/lib/ui/widgets/init_widget.dart +++ b/lib/ui/widgets/init_widget.dart @@ -108,7 +108,7 @@ class _InitializeWidgetState extends SafeState { if (_error || !WebSocketHelper.isConnected()) return _buildNonReadyWidget(); if (config().mainRouteBuilder != null) - return config().mainRouteBuilder(context); + return config().mainRouteBuilder(context, mainControllerKey); return isTablet(context) ? TabletRoute(key: mainControllerKey) diff --git a/lib/ui/widgets/status_widget.dart b/lib/ui/widgets/status_widget.dart new file mode 100644 index 0000000..49d6789 --- /dev/null +++ b/lib/ui/widgets/status_widget.dart @@ -0,0 +1,62 @@ +import 'package:comunic/helpers/events_helper.dart'; +import 'package:comunic/helpers/notifications_helper.dart'; +import 'package:comunic/ui/widgets/safe_state.dart'; +import 'package:comunic/utils/log_utils.dart'; +import 'package:flutter/material.dart'; + +/// Status widget +/// +/// Store for its children information about the number of unread conversations +/// & the number of unread conversations +/// +/// @author Pierre Hubert + +class StatusWidget extends StatefulWidget { + final Widget Function(BuildContext) child; + + const StatusWidget({ + Key key, + @required this.child, + }) : assert(child != null), + super(key: key); + + @override + StatusWidgetState createState() => StatusWidgetState(); +} + +class StatusWidgetState extends SafeState { + int unreadNotifications = 0; + int unreadConversations = 0; + + Future init() async { + try { + final res = await NotificationsHelper().countUnread(); + unreadNotifications = res.notifications; + unreadConversations = res.conversations; + + setState(() {}); + } catch (e, s) { + logError(e, s); + print("Failed to initialize StatusWidget!"); + } + } + + @override + void initState() { + init(); + super.initState(); + + listenChangeState( + (e) => unreadNotifications = e.newNum); + + listenChangeState( + (e) => unreadConversations = e.newNum); + } + + /// Find an ancestor of this object + static StatusWidgetState of(BuildContext c) => + c.findAncestorStateOfType(); + + @override + Widget build(BuildContext context) => widget.child(context); +} diff --git a/lib/ui/widgets/tab_transition_widget.dart b/lib/ui/widgets/tab_transition_widget.dart new file mode 100644 index 0000000..f06be52 --- /dev/null +++ b/lib/ui/widgets/tab_transition_widget.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +class TabTransitionWidget extends StatefulWidget { + final Widget child; + + const TabTransitionWidget(this.child, {Key key}) + : assert(child != null), + super(key: key); + + @override + _TabTransitionWidgetState createState() => _TabTransitionWidgetState(); +} + +class _TabTransitionWidgetState extends State { + var _show = false; + + @override + void initState() { + super.initState(); + Future.delayed(Duration(microseconds: 10)).then((value) { + if (mounted) setState(() => _show = true); + }); + } + + @override + Widget build(BuildContext context) { + if (!_show) + return Center(child: CircularProgressIndicator()); + else + return widget.child; + } +}