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

254 lines
8.3 KiB
Dart

import 'package:comunic/helpers/firebase_messaging_helper.dart';
import 'package:comunic/helpers/independent_push_notifications_helper.dart';
import 'package:comunic/helpers/push_notifications_helper.dart';
import 'package:comunic/helpers/server_config_helper.dart';
import 'package:comunic/models/config.dart';
import 'package:comunic/ui/widgets/async_screen_widget.dart';
import 'package:comunic/utils/flutter_utils.dart';
import 'package:comunic/utils/intl_utils.dart';
import 'package:comunic/utils/log_utils.dart';
import 'package:comunic/utils/ui_utils.dart';
import 'package:flutter/material.dart';
/// Push notifications configuration route
///
/// @author Pierre Hubert
Future<void> showInitialPushNotificationsConfiguration(
BuildContext context) async {
// Check if no notifications service are available
if (!PushNotificationsHelper.arePushNotificationsAvailable) return;
await Navigator.of(context).push(
MaterialPageRoute(builder: (c) => PushNotificationsConfigurationRoute()));
}
class PushNotificationsConfigurationRoute extends StatefulWidget {
@override
_PushNotificationsConfigurationRouteState createState() =>
_PushNotificationsConfigurationRouteState();
}
class _PushNotificationsConfigurationRouteState
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(),
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,
@required this.onChanged,
}) : super(key: key);
@override
PushNotificationsConfigurationWidgetState createState() =>
PushNotificationsConfigurationWidgetState();
}
class PushNotificationsConfigurationWidgetState
extends State<PushNotificationsConfigurationWidget> {
PushNotificationsStatus currStatus;
bool get canSubmit =>
(currStatus ?? PushNotificationsStatus.UNDEFINED) !=
PushNotificationsStatus.UNDEFINED;
Future<void> _refresh() async {
await PushNotificationsHelper.refreshLocalStatus();
currStatus = await PushNotificationsHelper.getLocalStatus();
if (currStatus == PushNotificationsStatus.UNDEFINED &&
srvConfig.notificationsPolicy.hasFirebase)
currStatus = PushNotificationsStatus.FIREBASE;
widget.onChanged();
}
@override
Widget build(BuildContext context) {
return AsyncScreenWidget(
onReload: _refresh,
onBuild: _buildForm,
errorMessage: tr("Failed to load push notifications settings!"),
);
}
Widget _buildForm() => ConstrainedBox(
constraints: BoxConstraints(maxWidth: 300),
child: Column(
children: [
Text(
tr("%app% can send you push notifications to your device.",
args: {
"app": config().appName,
}),
textAlign: TextAlign.center,
),
SizedBox(height: 10),
_NotificationOption(
title: tr("Use Google services (recommended)"),
description: tr("Save your battery life."),
option: PushNotificationsStatus.FIREBASE,
current: currStatus,
available: srvConfig.notificationsPolicy.hasFirebase,
onChanged: (s) {
setState(() => currStatus = s);
if (widget.onChanged != null) widget.onChanged();
},
),
SizedBox(height: 5),
_NotificationOption(
title: tr("Use independent notifications service"),
description: tr(
"Protect more your privacy, but drains battery and is less reliable."),
option: PushNotificationsStatus.INDEPENDENT,
current: currStatus,
available:
srvConfig.notificationsPolicy.hasIndependent && isAndroid,
onChanged: (s) {
setState(() => currStatus = s);
if (widget.onChanged != null) widget.onChanged();
},
),
SizedBox(height: 5),
_NotificationOption(
title: tr("Do not send notification"),
option: PushNotificationsStatus.DISABLED,
current: currStatus,
available: true,
onChanged: (s) {
setState(() => currStatus = s);
if (widget.onChanged != null) widget.onChanged();
},
),
],
),
);
Future<bool> submit() async {
try {
String firebaseToken = "";
if (currStatus == await PushNotificationsHelper.getLocalStatus()) {
widget.onConfigured();
return true;
}
switch (currStatus) {
case PushNotificationsStatus.DISABLED:
break;
case PushNotificationsStatus.FIREBASE:
await FirebaseMessagingHelper.preConfigure();
firebaseToken = await FirebaseMessagingHelper.getToken();
break;
case PushNotificationsStatus.INDEPENDENT:
if (await IndependentPushNotificationsHelper.needPreConfiguration())
await IndependentPushNotificationsHelper.preConfigure(context);
break;
default:
throw new Exception("Unknown status!");
}
await PushNotificationsHelper.clearLocalStatus();
await PushNotificationsHelper.setNewStatus(currStatus,
firebaseToken: firebaseToken);
await PushNotificationsHelper.refreshLocalStatus();
widget.onConfigured();
} catch (e, s) {
logError(e, s);
showAlert(
context: context,
message: tr("Failed to configure push notifications!"));
return false;
}
return true;
}
}
class _NotificationOption extends StatelessWidget {
final String title;
final String description;
final PushNotificationsStatus option;
final PushNotificationsStatus current;
final bool available;
final Function(PushNotificationsStatus) onChanged;
const _NotificationOption({
Key key,
@required this.title,
this.description,
@required this.option,
@required this.current,
@required this.available,
@required this.onChanged,
}) : assert(title != null),
assert(option != null),
assert(current != null),
assert(available != null),
assert(onChanged != null),
super(key: key);
@override
Widget build(BuildContext context) => !available
? Container()
: Theme(
data: Theme.of(context).copyWith(
splashColor: Colors.transparent,
highlightColor: Colors.transparent),
child: ListTile(
leading: Radio(
value: option,
groupValue: current,
onChanged: onChanged,
fillColor: MaterialStateProperty.all(Colors.white),
),
title: Text(title, style: TextStyle(color: Colors.white)),
subtitle: description == null
? null
: Text(description, style: TextStyle(color: Colors.white)),
contentPadding: EdgeInsets.all(0),
onTap: () => onChanged(option),
),
);
}