mirror of
				https://gitlab.com/comunic/comunicmobile
				synced 2025-11-03 19:54:12 +00:00 
			
		
		
		
	Can configure push notifications from tour
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
			
		||||
import 'package:comunic/helpers/preferences_helper.dart';
 | 
			
		||||
import 'package:comunic/helpers/users_helper.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/widgets/account_image_widget.dart';
 | 
			
		||||
import 'package:comunic/ui/widgets/async_screen_widget.dart';
 | 
			
		||||
@@ -25,6 +26,8 @@ class TourRoute extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
class _TourRouteState extends State<TourRoute> {
 | 
			
		||||
  final key = GlobalKey<AsyncScreenWidgetState>();
 | 
			
		||||
  final _pushNotificationsKey =
 | 
			
		||||
      GlobalKey<PushNotificationsConfigurationWidgetState>();
 | 
			
		||||
 | 
			
		||||
  User currUser;
 | 
			
		||||
 | 
			
		||||
@@ -37,6 +40,8 @@ class _TourRouteState extends State<TourRoute> {
 | 
			
		||||
 | 
			
		||||
  List<Widget> get _list => [
 | 
			
		||||
        _FirstPane(),
 | 
			
		||||
 | 
			
		||||
        // Account image
 | 
			
		||||
        _PresentationPane(
 | 
			
		||||
          iconWidget: AccountImageWidget(user: currUser, width: 50),
 | 
			
		||||
          title: tr("Account image"),
 | 
			
		||||
@@ -49,6 +54,20 @@ class _TourRouteState extends State<TourRoute> {
 | 
			
		||||
            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(
 | 
			
		||||
          icon: Icons.group_add,
 | 
			
		||||
          title: tr("Friends"),
 | 
			
		||||
@@ -111,6 +130,13 @@ class __RouteBodyState extends State<_RouteBody> {
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
  void didUpdateWidget(_RouteBody oldWidget) {
 | 
			
		||||
    super.didUpdateWidget(oldWidget);
 | 
			
		||||
@@ -134,12 +160,17 @@ class __RouteBodyState extends State<_RouteBody> {
 | 
			
		||||
        child: Column(
 | 
			
		||||
          children: <Widget>[
 | 
			
		||||
            Spacer(flex: 1),
 | 
			
		||||
            Expanded(child: TabBarView(children: widget.panes), flex: 5),
 | 
			
		||||
            Expanded(
 | 
			
		||||
                child: TabBarView(
 | 
			
		||||
                  children: widget.panes,
 | 
			
		||||
                  physics: NeverScrollableScrollPhysics(),
 | 
			
		||||
                ),
 | 
			
		||||
                flex: 10),
 | 
			
		||||
            Spacer(flex: 1),
 | 
			
		||||
            TabPageSelector(selectedColor: Colors.white),
 | 
			
		||||
            Spacer(flex: 1),
 | 
			
		||||
            OutlinedButton(
 | 
			
		||||
              onPressed: _nextOrFinish,
 | 
			
		||||
              onPressed: _canGoNext ? _nextOrFinish : null,
 | 
			
		||||
              child: Text(!_isLastPane ? tr("Next") : tr("Let's go!")),
 | 
			
		||||
            ),
 | 
			
		||||
            Spacer(flex: 1),
 | 
			
		||||
@@ -148,14 +179,19 @@ class __RouteBodyState extends State<_RouteBody> {
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
  void _nextOrFinish() async {
 | 
			
		||||
    if (!_controller.indexIsChanging) {
 | 
			
		||||
      if (!_isLastPane) {
 | 
			
		||||
        _controller.animateTo(_controller.index + 1);
 | 
			
		||||
      } else {
 | 
			
		||||
        (await PreferencesHelper.getInstance())
 | 
			
		||||
            .setBool(PreferencesKeyList.IS_TOUR_SEEN, true);
 | 
			
		||||
        Navigator.of(context).pop();
 | 
			
		||||
    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();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -165,26 +201,34 @@ class _PresentationPane extends StatelessWidget {
 | 
			
		||||
  final Widget iconWidget;
 | 
			
		||||
  final String title;
 | 
			
		||||
  final String text;
 | 
			
		||||
  final Function(BuildContext) child;
 | 
			
		||||
  final String actionTitle;
 | 
			
		||||
  final Function(BuildContext) onActionTap;
 | 
			
		||||
  final bool canGoNext;
 | 
			
		||||
  final Future<bool> Function(BuildContext) onTapNext;
 | 
			
		||||
 | 
			
		||||
  const _PresentationPane({
 | 
			
		||||
    Key key,
 | 
			
		||||
    this.icon,
 | 
			
		||||
    this.iconWidget,
 | 
			
		||||
    @required this.title,
 | 
			
		||||
    @required this.text,
 | 
			
		||||
    this.text,
 | 
			
		||||
    this.child,
 | 
			
		||||
    this.actionTitle,
 | 
			
		||||
    this.onActionTap,
 | 
			
		||||
    this.canGoNext = true,
 | 
			
		||||
    this.onTapNext,
 | 
			
		||||
  })  : assert(icon != null || iconWidget != null),
 | 
			
		||||
        assert(title != null),
 | 
			
		||||
        assert(text != null),
 | 
			
		||||
        assert(text != null || child != null),
 | 
			
		||||
        super(key: key);
 | 
			
		||||
 | 
			
		||||
  bool get _hasAction => actionTitle != null && onActionTap != null;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) => Column(
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    if (text != null)
 | 
			
		||||
      return Column(
 | 
			
		||||
        children: <Widget>[
 | 
			
		||||
          Spacer(flex: 3),
 | 
			
		||||
          icon != null ? Icon(icon, color: Colors.white, size: 50) : iconWidget,
 | 
			
		||||
@@ -214,6 +258,38 @@ class _PresentationPane extends StatelessWidget {
 | 
			
		||||
          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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,63 @@ class PushNotificationsConfigurationRoute extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
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(),
 | 
			
		||||
                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;
 | 
			
		||||
 | 
			
		||||
  bool get canSubmit =>
 | 
			
		||||
@@ -40,46 +97,36 @@ class _PushNotificationsConfigurationRouteState
 | 
			
		||||
  Future<void> _refresh() async {
 | 
			
		||||
    await PushNotificationsHelper.refreshLocalStatus();
 | 
			
		||||
    currStatus = await PushNotificationsHelper.getLocalStatus();
 | 
			
		||||
 | 
			
		||||
    if (currStatus == PushNotificationsStatus.UNDEFINED &&
 | 
			
		||||
        srvConfig.notificationsPolicy.hasFirebase)
 | 
			
		||||
      currStatus = PushNotificationsStatus.FIREBASE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Material(
 | 
			
		||||
        textStyle: TextStyle(color: Colors.white),
 | 
			
		||||
        color: config().splashBackgroundColor,
 | 
			
		||||
        child: Center(
 | 
			
		||||
          child: Padding(
 | 
			
		||||
            padding: const EdgeInsets.all(8.0),
 | 
			
		||||
            child: AsyncScreenWidget(
 | 
			
		||||
              onReload: _refresh,
 | 
			
		||||
              onBuild: _buildForm,
 | 
			
		||||
              errorMessage: tr("Failed to load push notifications settings!"),
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ));
 | 
			
		||||
    return AsyncScreenWidget(
 | 
			
		||||
      onReload: _refresh,
 | 
			
		||||
      onBuild: _buildForm,
 | 
			
		||||
      errorMessage: tr("Failed to load push notifications settings!"),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Widget _buildForm() => ConstrainedBox(
 | 
			
		||||
        constraints: BoxConstraints(maxWidth: 300),
 | 
			
		||||
        child: Column(
 | 
			
		||||
          mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
          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(
 | 
			
		||||
              title: tr("Use Google services"),
 | 
			
		||||
              title: tr("Use Google services (recommended)"),
 | 
			
		||||
              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."),
 | 
			
		||||
              option: PushNotificationsStatus.FIREBASE,
 | 
			
		||||
              current: currStatus,
 | 
			
		||||
              available: srvConfig.notificationsPolicy.hasFirebase,
 | 
			
		||||
              onChanged: (s) => setState(() => currStatus = s),
 | 
			
		||||
              onChanged: (s) {
 | 
			
		||||
                setState(() => currStatus = s);
 | 
			
		||||
                if (widget.onChanged != null) widget.onChanged();
 | 
			
		||||
              },
 | 
			
		||||
            ),
 | 
			
		||||
            _NotificationOption(
 | 
			
		||||
              title: tr("Use independent notifications service"),
 | 
			
		||||
@@ -89,7 +136,10 @@ class _PushNotificationsConfigurationRouteState
 | 
			
		||||
              current: currStatus,
 | 
			
		||||
              available:
 | 
			
		||||
                  srvConfig.notificationsPolicy.hasIndependent && isAndroid,
 | 
			
		||||
              onChanged: (s) => setState(() => currStatus = s),
 | 
			
		||||
              onChanged: (s) {
 | 
			
		||||
                setState(() => currStatus = s);
 | 
			
		||||
                if (widget.onChanged != null) widget.onChanged();
 | 
			
		||||
              },
 | 
			
		||||
            ),
 | 
			
		||||
            _NotificationOption(
 | 
			
		||||
              title: tr("Do not send notification"),
 | 
			
		||||
@@ -98,25 +148,22 @@ class _PushNotificationsConfigurationRouteState
 | 
			
		||||
              option: PushNotificationsStatus.DISABLED,
 | 
			
		||||
              current: currStatus,
 | 
			
		||||
              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 {
 | 
			
		||||
      String firebaseToken = "";
 | 
			
		||||
 | 
			
		||||
      if (currStatus == await PushNotificationsHelper.getLocalStatus()) {
 | 
			
		||||
        Navigator.of(context).pop();
 | 
			
		||||
        return;
 | 
			
		||||
        widget.onConfigured();
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      switch (currStatus) {
 | 
			
		||||
@@ -142,13 +189,15 @@ class _PushNotificationsConfigurationRouteState
 | 
			
		||||
          firebaseToken: firebaseToken);
 | 
			
		||||
      await PushNotificationsHelper.refreshLocalStatus();
 | 
			
		||||
 | 
			
		||||
      Navigator.of(context).pop();
 | 
			
		||||
      widget.onConfigured();
 | 
			
		||||
    } catch (e, s) {
 | 
			
		||||
      logError(e, s);
 | 
			
		||||
      showAlert(
 | 
			
		||||
          context: context,
 | 
			
		||||
          message: tr("Failed to configure push notifications!"));
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user