mirror of
https://gitlab.com/comunic/comunicmobile
synced 2024-11-22 04:49:21 +00:00
231 lines
7.3 KiB
Dart
231 lines
7.3 KiB
Dart
import 'package:comunic/helpers/preferences_helper.dart';
|
|
import 'package:comunic/helpers/push_notifications_helper.dart';
|
|
import 'package:comunic/helpers/server_config_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:comunic/utils/log_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()));
|
|
|
|
typedef TourEntriesBuilder = List<Widget> Function(TourRouteState);
|
|
|
|
class TourRoute extends StatefulWidget {
|
|
@override
|
|
TourRouteState createState() => TourRouteState();
|
|
}
|
|
|
|
class TourRouteState extends State<TourRoute> {
|
|
final _key = GlobalKey<AsyncScreenWidgetState>();
|
|
final pushNotificationsKey =
|
|
GlobalKey<PushNotificationsConfigurationWidgetState>();
|
|
|
|
final Map<int, GlobalKey> pubKeys = Map();
|
|
|
|
late User currUser;
|
|
|
|
int _defaultIndex = 0;
|
|
|
|
bool areNotificationsConfigured = false;
|
|
|
|
Future<void> _init() async {
|
|
currUser =
|
|
await UsersHelper().getSingleWithThrow(userID(), forceDownload: true);
|
|
|
|
// Pre-configure notifications
|
|
final notificationsStatus = await PushNotificationsHelper.getLocalStatus();
|
|
if (!PushNotificationsHelper.arePushNotificationsAvailable ||
|
|
notificationsStatus != PushNotificationsStatus.UNDEFINED)
|
|
areNotificationsConfigured = true;
|
|
|
|
// Attempt to automatically register to FCM
|
|
else if (srvConfig!.notificationsPolicy.hasFirebase) {
|
|
try {
|
|
await PushNotificationsHelper.configure(
|
|
context, PushNotificationsStatus.FIREBASE);
|
|
areNotificationsConfigured = true;
|
|
} catch (e, s) {
|
|
logError(e, s);
|
|
}
|
|
}
|
|
}
|
|
|
|
void rebuild() => setState(() {});
|
|
|
|
void setStateKeepCurrentIndex(BuildContext cxt) async {
|
|
_defaultIndex = DefaultTabController.of(cxt)!.index;
|
|
await _key.currentState!.refresh();
|
|
}
|
|
|
|
List<Widget> get _list => (config().toursEntriesBuilder != null
|
|
? config().toursEntriesBuilder!(this)
|
|
: [
|
|
FirstTourPane(),
|
|
|
|
// Account image
|
|
AccountImageTourPane(
|
|
user: currUser,
|
|
onUpdated: setStateKeepCurrentIndex,
|
|
),
|
|
|
|
// Notifications
|
|
TourNotificationsPane(
|
|
pushNotificationsKey: pushNotificationsKey,
|
|
onConfigured: () => setState(() {}),
|
|
onChanged: () => setState(() {}),
|
|
visible: !areNotificationsConfigured,
|
|
),
|
|
|
|
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\n${tr("This 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\n${tr("It 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\n${tr("It 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\n${tr("If you do not trust us, you can always check out our source code to verify it!")}",
|
|
),
|
|
LastTourPane(),
|
|
])
|
|
..removeWhere((pane) {
|
|
if (pane is PresentationPane) {
|
|
PresentationPane p = pane;
|
|
return !(p.visible);
|
|
}
|
|
return false;
|
|
});
|
|
|
|
@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<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] as PresentationPane?
|
|
: 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: <Widget>[
|
|
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();
|
|
}
|
|
}
|
|
}
|