1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-25 14:29:22 +00:00

Can configure push notifications from tour

This commit is contained in:
Pierre HUBERT 2021-04-17 19:19:55 +02:00
parent 899270961a
commit 116e6ce66d
2 changed files with 173 additions and 48 deletions

View File

@ -1,6 +1,7 @@
import 'package:comunic/helpers/preferences_helper.dart'; import 'package:comunic/helpers/preferences_helper.dart';
import 'package:comunic/helpers/users_helper.dart'; import 'package:comunic/helpers/users_helper.dart';
import 'package:comunic/models/user.dart'; import 'package:comunic/models/user.dart';
import 'package:comunic/ui/routes/push_notifications_route.dart';
import 'package:comunic/ui/routes/settings/account_image_settings.dart'; import 'package:comunic/ui/routes/settings/account_image_settings.dart';
import 'package:comunic/ui/widgets/account_image_widget.dart'; import 'package:comunic/ui/widgets/account_image_widget.dart';
import 'package:comunic/ui/widgets/async_screen_widget.dart'; import 'package:comunic/ui/widgets/async_screen_widget.dart';
@ -25,6 +26,8 @@ class TourRoute extends StatefulWidget {
class _TourRouteState extends State<TourRoute> { class _TourRouteState extends State<TourRoute> {
final key = GlobalKey<AsyncScreenWidgetState>(); final key = GlobalKey<AsyncScreenWidgetState>();
final _pushNotificationsKey =
GlobalKey<PushNotificationsConfigurationWidgetState>();
User currUser; User currUser;
@ -37,6 +40,8 @@ class _TourRouteState extends State<TourRoute> {
List<Widget> get _list => [ List<Widget> get _list => [
_FirstPane(), _FirstPane(),
// Account image
_PresentationPane( _PresentationPane(
iconWidget: AccountImageWidget(user: currUser, width: 50), iconWidget: AccountImageWidget(user: currUser, width: 50),
title: tr("Account image"), title: tr("Account image"),
@ -49,6 +54,20 @@ class _TourRouteState extends State<TourRoute> {
await key.currentState.refresh(); 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(),
),
_PresentationPane( _PresentationPane(
icon: Icons.group_add, icon: Icons.group_add,
title: tr("Friends"), title: tr("Friends"),
@ -111,6 +130,13 @@ class __RouteBodyState extends State<_RouteBody> {
bool get _isLastPane => _controller.index >= widget.panes.length - 1; 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 @override
void didUpdateWidget(_RouteBody oldWidget) { void didUpdateWidget(_RouteBody oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
@ -134,12 +160,17 @@ class __RouteBodyState extends State<_RouteBody> {
child: Column( child: Column(
children: <Widget>[ children: <Widget>[
Spacer(flex: 1), Spacer(flex: 1),
Expanded(child: TabBarView(children: widget.panes), flex: 5), Expanded(
child: TabBarView(
children: widget.panes,
physics: NeverScrollableScrollPhysics(),
),
flex: 10),
Spacer(flex: 1), Spacer(flex: 1),
TabPageSelector(selectedColor: Colors.white), TabPageSelector(selectedColor: Colors.white),
Spacer(flex: 1), Spacer(flex: 1),
OutlinedButton( OutlinedButton(
onPressed: _nextOrFinish, onPressed: _canGoNext ? _nextOrFinish : null,
child: Text(!_isLastPane ? tr("Next") : tr("Let's go!")), child: Text(!_isLastPane ? tr("Next") : tr("Let's go!")),
), ),
Spacer(flex: 1), Spacer(flex: 1),
@ -148,14 +179,19 @@ class __RouteBodyState extends State<_RouteBody> {
); );
void _nextOrFinish() async { void _nextOrFinish() async {
if (!_controller.indexIsChanging) { if (_controller.indexIsChanging) return;
if (!_isLastPane) {
_controller.animateTo(_controller.index + 1); if (!_isLastPane) {
} else { // Check if the next click has to be captured
(await PreferencesHelper.getInstance()) if (_currPane?.onTapNext != null) {
.setBool(PreferencesKeyList.IS_TOUR_SEEN, true); if (!await _currPane.onTapNext(context)) return;
Navigator.of(context).pop();
} }
_controller.animateTo(_controller.index + 1);
} else {
(await PreferencesHelper.getInstance())
.setBool(PreferencesKeyList.IS_TOUR_SEEN, true);
Navigator.of(context).pop();
} }
} }
} }
@ -165,26 +201,34 @@ class _PresentationPane extends StatelessWidget {
final Widget iconWidget; final Widget iconWidget;
final String title; final String title;
final String text; final String text;
final Function(BuildContext) child;
final String actionTitle; final String actionTitle;
final Function(BuildContext) onActionTap; final Function(BuildContext) onActionTap;
final bool canGoNext;
final Future<bool> Function(BuildContext) onTapNext;
const _PresentationPane({ const _PresentationPane({
Key key, Key key,
this.icon, this.icon,
this.iconWidget, this.iconWidget,
@required this.title, @required this.title,
@required this.text, this.text,
this.child,
this.actionTitle, this.actionTitle,
this.onActionTap, this.onActionTap,
this.canGoNext = true,
this.onTapNext,
}) : assert(icon != null || iconWidget != null), }) : assert(icon != null || iconWidget != null),
assert(title != null), assert(title != null),
assert(text != null), assert(text != null || child != null),
super(key: key); super(key: key);
bool get _hasAction => actionTitle != null && onActionTap != null; bool get _hasAction => actionTitle != null && onActionTap != null;
@override @override
Widget build(BuildContext context) => Column( Widget build(BuildContext context) {
if (text != null)
return Column(
children: <Widget>[ children: <Widget>[
Spacer(flex: 3), Spacer(flex: 3),
icon != null ? Icon(icon, color: Colors.white, size: 50) : iconWidget, icon != null ? Icon(icon, color: Colors.white, size: 50) : iconWidget,
@ -214,6 +258,38 @@ class _PresentationPane extends StatelessWidget {
Spacer(flex: 3), 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),
child(context),
Spacer(flex: 1),
_hasAction
? OutlinedButton(
onPressed: () => onActionTap(context),
child: Text(
actionTitle,
style: TextStyle(color: Colors.white),
),
)
: Opacity(
opacity: 0,
child: OutlinedButton(
onPressed: null,
child: Text(""),
),
),
Spacer(flex: 1),
],
);
}
} }
class _FirstPane extends StatelessWidget { class _FirstPane extends StatelessWidget {

View File

@ -31,6 +31,63 @@ class PushNotificationsConfigurationRoute extends StatefulWidget {
class _PushNotificationsConfigurationRouteState class _PushNotificationsConfigurationRouteState
extends State<PushNotificationsConfigurationRoute> { extends State<PushNotificationsConfigurationRoute> {
final _key = GlobalKey<PushNotificationsConfigurationWidgetState>();
@override
Widget build(BuildContext context) => Material(
textStyle: TextStyle(color: Colors.white),
color: config().splashBackgroundColor,
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Spacer(),
Icon(Icons.notifications_none, color: Colors.white),
Spacer(),
Text(
tr("Comunic can send you notifications to your device when the application is closed if you want."),
textAlign: TextAlign.center,
),
Spacer(),
PushNotificationsConfigurationWidget(
key: _key,
onConfigured: () => (Navigator.of(context).pop()),
onChanged: () => setState(() {}),
),
Spacer(),
OutlinedButton(
onPressed: _key?.currentState?.canSubmit ?? false
? _key.currentState.submit
: null,
child: Text(tr("Configure").toUpperCase()),
style: OutlinedButton.styleFrom(primary: Colors.white)),
Spacer(),
],
),
),
),
);
}
class PushNotificationsConfigurationWidget extends StatefulWidget {
final Function() onConfigured;
final Function() onChanged;
const PushNotificationsConfigurationWidget({
Key key,
@required this.onConfigured,
this.onChanged,
}) : super(key: key);
@override
PushNotificationsConfigurationWidgetState createState() =>
PushNotificationsConfigurationWidgetState();
}
class PushNotificationsConfigurationWidgetState
extends State<PushNotificationsConfigurationWidget> {
PushNotificationsStatus currStatus; PushNotificationsStatus currStatus;
bool get canSubmit => bool get canSubmit =>
@ -40,46 +97,36 @@ class _PushNotificationsConfigurationRouteState
Future<void> _refresh() async { Future<void> _refresh() async {
await PushNotificationsHelper.refreshLocalStatus(); await PushNotificationsHelper.refreshLocalStatus();
currStatus = await PushNotificationsHelper.getLocalStatus(); currStatus = await PushNotificationsHelper.getLocalStatus();
if (currStatus == PushNotificationsStatus.UNDEFINED &&
srvConfig.notificationsPolicy.hasFirebase)
currStatus = PushNotificationsStatus.FIREBASE;
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Material( return AsyncScreenWidget(
textStyle: TextStyle(color: Colors.white), onReload: _refresh,
color: config().splashBackgroundColor, onBuild: _buildForm,
child: Center( errorMessage: tr("Failed to load push notifications settings!"),
child: Padding( );
padding: const EdgeInsets.all(8.0),
child: AsyncScreenWidget(
onReload: _refresh,
onBuild: _buildForm,
errorMessage: tr("Failed to load push notifications settings!"),
),
),
));
} }
Widget _buildForm() => ConstrainedBox( Widget _buildForm() => ConstrainedBox(
constraints: BoxConstraints(maxWidth: 300), constraints: BoxConstraints(maxWidth: 300),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Spacer(),
Icon(Icons.notifications_none, color: Colors.white),
Spacer(),
Text(
tr("Comunic can now send you notifications to your device when the application is closed if you want."),
textAlign: TextAlign.center,
),
Spacer(),
_NotificationOption( _NotificationOption(
title: tr("Use Google services"), title: tr("Use Google services (recommended)"),
description: tr( description: tr(
"Use the Google Play services to send you notifications. This option is less privacy-friendly, but it will work on most phones and will save your battery life."), "Use the Google Play services to send you notifications. This option is less privacy-friendly, but it will work on most phones and will save your battery life."),
option: PushNotificationsStatus.FIREBASE, option: PushNotificationsStatus.FIREBASE,
current: currStatus, current: currStatus,
available: srvConfig.notificationsPolicy.hasFirebase, available: srvConfig.notificationsPolicy.hasFirebase,
onChanged: (s) => setState(() => currStatus = s), onChanged: (s) {
setState(() => currStatus = s);
if (widget.onChanged != null) widget.onChanged();
},
), ),
_NotificationOption( _NotificationOption(
title: tr("Use independent notifications service"), title: tr("Use independent notifications service"),
@ -89,7 +136,10 @@ class _PushNotificationsConfigurationRouteState
current: currStatus, current: currStatus,
available: available:
srvConfig.notificationsPolicy.hasIndependent && isAndroid, srvConfig.notificationsPolicy.hasIndependent && isAndroid,
onChanged: (s) => setState(() => currStatus = s), onChanged: (s) {
setState(() => currStatus = s);
if (widget.onChanged != null) widget.onChanged();
},
), ),
_NotificationOption( _NotificationOption(
title: tr("Do not send notification"), title: tr("Do not send notification"),
@ -98,25 +148,22 @@ class _PushNotificationsConfigurationRouteState
option: PushNotificationsStatus.DISABLED, option: PushNotificationsStatus.DISABLED,
current: currStatus, current: currStatus,
available: true, available: true,
onChanged: (s) => setState(() => currStatus = s), onChanged: (s) {
setState(() => currStatus = s);
if (widget.onChanged != null) widget.onChanged();
},
), ),
Spacer(),
OutlinedButton(
onPressed: canSubmit ? _submit : null,
child: Text(tr("Configure").toUpperCase()),
style: OutlinedButton.styleFrom(primary: Colors.white)),
Spacer(),
], ],
), ),
); );
Future<void> _submit() async { Future<bool> submit() async {
try { try {
String firebaseToken = ""; String firebaseToken = "";
if (currStatus == await PushNotificationsHelper.getLocalStatus()) { if (currStatus == await PushNotificationsHelper.getLocalStatus()) {
Navigator.of(context).pop(); widget.onConfigured();
return; return true;
} }
switch (currStatus) { switch (currStatus) {
@ -142,13 +189,15 @@ class _PushNotificationsConfigurationRouteState
firebaseToken: firebaseToken); firebaseToken: firebaseToken);
await PushNotificationsHelper.refreshLocalStatus(); await PushNotificationsHelper.refreshLocalStatus();
Navigator.of(context).pop(); widget.onConfigured();
} catch (e, s) { } catch (e, s) {
logError(e, s); logError(e, s);
showAlert( showAlert(
context: context, context: context,
message: tr("Failed to configure push notifications!")); message: tr("Failed to configure push notifications!"));
return false;
} }
return true;
} }
} }