1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-25 22:39:22 +00:00
comunicmobile/lib/ui/routes/TourRoute.dart

327 lines
9.5 KiB
Dart
Raw Normal View History

2021-04-17 16:05:33 +00:00
import 'package:comunic/helpers/preferences_helper.dart';
2021-04-17 16:33:08 +00:00
import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/models/user.dart';
import 'package:comunic/ui/routes/push_notifications_route.dart';
2021-04-17 16:33:08 +00:00
import 'package:comunic/ui/routes/settings/account_image_settings.dart';
import 'package:comunic/ui/widgets/account_image_widget.dart';
import 'package:comunic/ui/widgets/async_screen_widget.dart';
2021-04-17 16:05:33 +00:00
import 'package:comunic/ui/widgets/login_routes_theme.dart';
2021-04-17 16:33:08 +00:00
import 'package:comunic/utils/account_utils.dart';
2021-04-17 16:05:33 +00:00
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<void> showTour(BuildContext context) async => await Navigator.of(context)
.push(MaterialPageRoute(builder: (c) => TourRoute()));
class TourRoute extends StatefulWidget {
@override
_TourRouteState createState() => _TourRouteState();
}
class _TourRouteState extends State<TourRoute> {
2021-04-17 16:33:08 +00:00
final key = GlobalKey<AsyncScreenWidgetState>();
final _pushNotificationsKey =
GlobalKey<PushNotificationsConfigurationWidgetState>();
2021-04-17 16:33:08 +00:00
User currUser;
int _defaultIndex = 0;
Future<void> _init() async {
currUser =
await UsersHelper().getSingleWithThrow(userID(), forceDownload: true);
}
2021-04-17 16:05:33 +00:00
List<Widget> get _list => [
_FirstPane(),
// Account image
2021-04-17 16:33:08 +00:00
_PresentationPane(
iconWidget: AccountImageWidget(user: currUser, width: 50),
title: tr("Account image"),
text: tr(
"Account image allow to quickly recognize people.\n\nYou can decide to define one now!"),
actionTitle: tr("Upload an account image"),
onActionTap: (ctx) async {
await uploadNewAccountImage(context);
_defaultIndex = DefaultTabController.of(ctx).index;
await key.currentState.refresh();
},
),
// Notifications
_PresentationPane(
icon: Icons.notifications,
title: tr("Push notifications"),
child: (c) => PushNotificationsConfigurationWidget(
key: _pushNotificationsKey,
onConfigured: () => setState(() {}),
onChanged: () => setState(() {}),
),
canGoNext: _pushNotificationsKey?.currentState?.canSubmit ?? false,
onTapNext: (c) => _pushNotificationsKey.currentState.submit(),
),
2021-04-17 16:05:33 +00:00
_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!"),
),
_LastPane(),
];
@override
Widget build(BuildContext context) => LoginRoutesTheme(
child: Scaffold(
body: SafeArea(
2021-04-17 16:33:08 +00:00
child: AsyncScreenWidget(
key: key,
onReload: _init,
errorMessage: tr("Failed to load tour!"),
onBuild: () => DefaultTabController(
initialIndex: _defaultIndex,
2021-04-17 16:05:33 +00:00
length: _list.length,
2021-04-17 16:33:08 +00:00
child: _RouteBody(
panes: _list,
),
2021-04-17 16:05:33 +00:00
),
),
),
),
);
}
class _RouteBody extends StatefulWidget {
final List<Widget> 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;
2021-04-17 16:05:33 +00:00
@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: <Widget>[
Spacer(flex: 1),
Expanded(
child: TabBarView(
children: widget.panes,
physics: NeverScrollableScrollPhysics(),
),
flex: 10),
2021-04-17 16:05:33 +00:00
Spacer(flex: 1),
TabPageSelector(selectedColor: Colors.white),
Spacer(flex: 1),
OutlinedButton(
onPressed: _canGoNext ? _nextOrFinish : null,
2021-04-17 16:05:33 +00:00
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;
2021-04-17 16:05:33 +00:00
}
_controller.animateTo(_controller.index + 1);
} else {
(await PreferencesHelper.getInstance())
.setBool(PreferencesKeyList.IS_TOUR_SEEN, true);
Navigator.of(context).pop();
2021-04-17 16:05:33 +00:00
}
}
}
class _PresentationPane extends StatelessWidget {
final IconData icon;
2021-04-17 16:33:08 +00:00
final Widget iconWidget;
2021-04-17 16:05:33 +00:00
final String title;
final String text;
final Function(BuildContext) child;
2021-04-17 16:05:33 +00:00
final String actionTitle;
2021-04-17 16:33:08 +00:00
final Function(BuildContext) onActionTap;
final bool canGoNext;
final Future<bool> Function(BuildContext) onTapNext;
2021-04-17 16:05:33 +00:00
const _PresentationPane({
Key key,
2021-04-17 16:33:08 +00:00
this.icon,
this.iconWidget,
2021-04-17 16:05:33 +00:00
@required this.title,
this.text,
this.child,
2021-04-17 16:05:33 +00:00
this.actionTitle,
this.onActionTap,
this.canGoNext = true,
this.onTapNext,
2021-04-17 16:33:08 +00:00
}) : assert(icon != null || iconWidget != null),
2021-04-17 16:05:33 +00:00
assert(title != null),
assert(text != null || child != null),
2021-04-17 16:05:33 +00:00
super(key: key);
bool get _hasAction => actionTitle != null && onActionTap != null;
@override
Widget build(BuildContext context) {
if (text != null)
return Column(
2021-04-17 16:05:33 +00:00
children: <Widget>[
Spacer(flex: 3),
2021-04-17 16:33:08 +00:00
icon != null ? Icon(icon, color: Colors.white, size: 50) : iconWidget,
2021-04-17 16:05:33 +00:00
Spacer(flex: 1),
Text(
title,
style: TextStyle(fontSize: 20),
),
Spacer(flex: 1),
_FixedSizeTextArea(text),
Spacer(flex: 1),
_hasAction
? OutlinedButton(
2021-04-17 16:33:08 +00:00
onPressed: () => onActionTap(context),
2021-04-17 16:05:33 +00:00
child: Text(
actionTitle,
style: TextStyle(color: Colors.white),
),
)
: Opacity(
opacity: 0,
child: OutlinedButton(
onPressed: null,
child: Text(""),
),
),
Spacer(flex: 3),
],
);
return Column(
children: <Widget>[
Spacer(flex: 1),
icon != null ? Icon(icon, color: Colors.white, size: 50) : iconWidget,
Spacer(flex: 1),
Text(
title,
style: TextStyle(fontSize: 20),
),
Spacer(flex: 1),
2021-04-17 17:29:22 +00:00
ConstrainedBox(
constraints: BoxConstraints(maxHeight: 300),
child: SingleChildScrollView(child: child(context))),
Spacer(flex: 1),
],
);
}
2021-04-17 16:05:33 +00:00
}
class _FirstPane extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Spacer(flex: 3),
Text(
"Comunic",
style: TextStyle(fontSize: 25),
),
Spacer(flex: 2),
_FixedSizeTextArea(tr(
"Welcome to Comunic, the social network that respect your privacy !")),
Spacer(flex: 1),
2021-04-17 16:33:08 +00:00
_FixedSizeTextArea(tr(
"Let's configure a few things and present you some features of the network...")),
2021-04-17 16:05:33 +00:00
Spacer(flex: 3),
],
);
}
}
class _LastPane extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Text(
tr("The application is yours"),
style: TextStyle(fontSize: 25),
),
);
}
}
class _FixedSizeTextArea extends StatelessWidget {
final String text;
const _FixedSizeTextArea(this.text);
@override
Widget build(BuildContext context) => ConstrainedBox(
constraints: BoxConstraints(maxWidth: 300),
child: Text(text, textAlign: TextAlign.justify),
);
}