import 'package:comunic/helpers/preferences_helper.dart'; import 'package:comunic/helpers/users_helper.dart'; import 'package:comunic/models/config.dart'; import 'package:comunic/models/user.dart'; import 'package:comunic/ui/routes/push_notifications_route.dart'; import 'package:comunic/ui/widgets/async_screen_widget.dart'; import 'package:comunic/ui/widgets/login_routes_theme.dart'; import 'package:comunic/ui/widgets/tour/account_image_tour_pane.dart'; import 'package:comunic/ui/widgets/tour/first_pane.dart'; import 'package:comunic/ui/widgets/tour/last_pane.dart'; import 'package:comunic/ui/widgets/tour/presentation_pane.dart'; import 'package:comunic/ui/widgets/tour/tour_notifications_pane.dart'; import 'package:comunic/utils/account_utils.dart'; import 'package:comunic/utils/intl_utils.dart'; import 'package:flutter/material.dart'; /// Tour route /// /// The tour is shown when the client sign into the application /// /// @author Pierre Hubert Future showTour(BuildContext context) async => await Navigator.of(context) .push(MaterialPageRoute(builder: (c) => TourRoute())); typedef TourEntriesBuilder = List Function(TourRouteState); class TourRoute extends StatefulWidget { @override TourRouteState createState() => TourRouteState(); } class TourRouteState extends State { final _key = GlobalKey(); final pushNotificationsKey = GlobalKey(); final Map pubKeys = Map(); User currUser; int _defaultIndex = 0; Future _init() async { currUser = await UsersHelper().getSingleWithThrow(userID(), forceDownload: true); } void rebuild() => setState(() {}); void setStateKeepCurrentIndex(BuildContext cxt) async { _defaultIndex = DefaultTabController.of(cxt).index; await _key.currentState.refresh(); } List get _list => config().toursEntriesBuilder != null ? config().toursEntriesBuilder(this) : [ FirstTourPane(), // Account image AccountImageTourPane( user: currUser, onUpdated: setStateKeepCurrentIndex, ), // Notifications TourNotificationsPane( pushNotificationsKey: pushNotificationsKey, onConfigured: () => setState(() {}), onChanged: () => setState(() {}), ), PresentationPane( icon: Icons.group_add, title: tr("Friends"), text: tr( "You can search the people you know and ask them to become your friends!\n\nThis will help you to reach them to exchange information!"), ), PresentationPane( icon: Icons.question_answer, title: tr("Conversations"), text: tr( "With Comunic, you can have conversations with all your friends.\n\nIt is also possible to make video calls!"), ), PresentationPane( icon: Icons.group, title: tr("Groups"), text: tr( "You can join groups where people share the same interests as you!\n\nIt is also easy to create your own groups!"), ), PresentationPane( icon: Icons.lock, title: tr("Privacy"), text: tr( "Your data is YOUR DATA. We will never use it or sell it.\n\nIf you do not trust us, you can always check out our source code to verify it!"), ), LastTourPane(), ]; @override Widget build(BuildContext context) => LoginRoutesTheme( child: Scaffold( body: SafeArea( child: AsyncScreenWidget( key: _key, onReload: _init, errorMessage: tr("Failed to load tour!"), onBuild: () => DefaultTabController( initialIndex: _defaultIndex, length: _list.length, child: _RouteBody( panes: _list, ), ), ), ), ), ); } class _RouteBody extends StatefulWidget { final List panes; const _RouteBody({Key key, this.panes}) : super(key: key); @override __RouteBodyState createState() => __RouteBodyState(); } class __RouteBodyState extends State<_RouteBody> { TabController _controller; bool get _isLastPane => _controller.index >= widget.panes.length - 1; PresentationPane get _currPane => widget.panes[_controller.index] is PresentationPane ? widget.panes[_controller.index] : null; bool get _canGoNext => _currPane?.canGoNext ?? true; @override void didUpdateWidget(_RouteBody oldWidget) { super.didUpdateWidget(oldWidget); _updateController(); } @override void didChangeDependencies() { super.didChangeDependencies(); _updateController(); } void _updateController() { _controller = DefaultTabController.of(context); _controller.addListener(() => setState(() {})); } @override Widget build(BuildContext context) => Padding( padding: const EdgeInsets.all(8.0), child: Column( children: [ Spacer(flex: 1), Expanded( child: TabBarView( children: widget.panes, physics: NeverScrollableScrollPhysics(), ), flex: 10), Spacer(flex: 1), TabPageSelector(selectedColor: Colors.white), Spacer(flex: 1), OutlinedButton( onPressed: _canGoNext ? _nextOrFinish : null, child: Text(!_isLastPane ? tr("Next") : tr("Let's go!")), ), Spacer(flex: 1), ], ), ); void _nextOrFinish() async { if (_controller.indexIsChanging) return; if (!_isLastPane) { // Check if the next click has to be captured if (_currPane?.onTapNext != null) { if (!await _currPane.onTapNext(context)) return; } _controller.animateTo(_controller.index + 1); } else { (await PreferencesHelper.getInstance()) .setBool(PreferencesKeyList.IS_TOUR_SEEN, true); Navigator.of(context).pop(); } } }