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 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 { final _key = GlobalKey(); @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 { PushNotificationsStatus? currStatus; bool get canSubmit => (currStatus ?? PushNotificationsStatus.UNDEFINED) != PushNotificationsStatus.UNDEFINED; Future _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 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); 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); widget.onChanged(); }, ), SizedBox(height: 5), _NotificationOption( title: tr("Do not send notification")!, option: PushNotificationsStatus.DISABLED, current: currStatus!, available: true, onChanged: (s) { setState(() => currStatus = s); widget.onChanged(); }, ), ], ), ); Future submit() async { try { if (currStatus == await PushNotificationsHelper.getLocalStatus()) { widget.onConfigured(); return true; } await PushNotificationsHelper.configure(context, currStatus); 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, }) : 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), ), ); }