Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add modal sheet on app startup to ask missing notification permissions
Browse files Browse the repository at this point in the history
iqfareez committed Mar 28, 2024
1 parent 45b3bfc commit 71d374e
Showing 5 changed files with 227 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';

class ExactAlarmPermissionOffSheet extends StatelessWidget {
const ExactAlarmPermissionOffSheet({
super.key,
required this.onGrantPermission,
required this.onCancelModal,
});

/// What will happen when "Give permission" button is pressed
final VoidCallback onGrantPermission;

/// What will happen when "Cancel" button is pressed
final VoidCallback onCancelModal;

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Padding(
padding: EdgeInsets.all(24.0),
child: Icon(Icons.notifications_active_outlined, size: 80),
),
const SizedBox(height: 8),
const Text(
'We require one more permission to trigger the notification/azan at the right time',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
const Text(
'This permission is needed to push the notification at the correct time. If you say no, the app might still schedule the notification, but the delivery may be delayed.',
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
),
onPressed: onGrantPermission,
child: const Text('Grant now'),
),
TextButton(
onPressed: onCancelModal,
child: const Text('Cancel'),
),
],
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';

class NotificationPermissionOffSheet extends StatelessWidget {
const NotificationPermissionOffSheet({
super.key,
required this.onTurnOnNotification,
required this.onCancelModal,
});

/// What will happen when "Turn On Notification" button is pressed
final VoidCallback onTurnOnNotification;

/// What will happen when "Keep it off for now" button is pressed
final VoidCallback onCancelModal;

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Padding(
padding: EdgeInsets.all(24.0),
child: Icon(Icons.notifications_off_outlined, size: 80),
),
const SizedBox(height: 8),
const Text(
'Notification/Azan is turned off',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
const Text(
'We may require some permissions to be able to play the notification/azan',
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Theme.of(context).colorScheme.primary,
foregroundColor: Theme.of(context).colorScheme.onPrimary,
),
onPressed: onTurnOnNotification,
child: const Text('Turn On Notification'),
),
TextButton(
onPressed: onCancelModal,
child: const Text('Keep it off for now'),
),
],
),
);
}
}
72 changes: 60 additions & 12 deletions lib/views/app_body.dart
Original file line number Diff line number Diff line change
@@ -4,14 +4,18 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get_storage/get_storage.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:provider/provider.dart';

import '../constants.dart';
import '../features/home/views/components/exact_alarm_permission_off_sheet.dart';
import '../features/home/views/components/notification_permission_off_sheet.dart';
import '../location_utils/location_database.dart';
import '../providers/location_provider.dart';
import '../providers/updater_provider.dart';
@@ -37,7 +41,7 @@ class _AppBodyState extends State<AppBody> {

_checkForUpdate();
_showUpdateNotesAndNotFirstRun();
_requestScheduleNotificationPermission();
_promptScheduleNotificationPermission();
}

void _checkForUpdate() async {
@@ -73,19 +77,63 @@ class _AppBodyState extends State<AppBody> {

/// Request schedule notification permission. The permission already requested from the onboarding page,
/// but for users that have their system upgraded, the permission will be requested here.
void _requestScheduleNotificationPermission() async {
debugPrint('Requesting notification permission');
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final androidNotif =
flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
final permissionGranted =
await androidNotif?.canScheduleExactNotifications() ?? false;
void _promptScheduleNotificationPermission() async {
// First, check is notification is enabled at all
final isNotificationGranted = await Permission.notification.status;
debugPrint('Notification permission status: $isNotificationGranted');

if (!permissionGranted) {
androidNotif?.requestNotificationsPermission();
if (!isNotificationGranted.isGranted) {
final PermissionStatus? status = await showModalBottomSheet(
context: context,
builder: (_) {
return NotificationPermissionOffSheet(
onTurnOnNotification: () async {
final res = await Permission.notification.request();
Navigator.pop(context, res);
},
onCancelModal: () {
Navigator.pop(context);
},
);
},
);

if (status != PermissionStatus.granted) {
// TODO: Show toast to tell this setting can be found in the settings
return; // Will not trigger the next checking for exact alarm permission
}
}

final isScheduleExactAlarmGranted =
await Permission.scheduleExactAlarm.status;
debugPrint(
'Schedule exact alarm permission status: $isScheduleExactAlarmGranted');

if (isScheduleExactAlarmGranted.isGranted) return;

final PermissionStatus? exactAlarmStatus = await showModalBottomSheet(
context: context,
builder: (_) {
return ExactAlarmPermissionOffSheet(
onGrantPermission: () async {
final res = await Permission.scheduleExactAlarm.request();
Navigator.pop(context, res);
},
onCancelModal: () {
Navigator.pop(context);
// TODO: Show toast to tell this setting can be found in the settings
},
);
},
);

if (exactAlarmStatus != PermissionStatus.granted) {
// TODO: Show another modal says to open settings later
return;
}

Fluttertoast.showToast(
msg: 'Thank you for granting the permissions needed');
}

@override
48 changes: 48 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
@@ -799,6 +799,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.1"
permission_handler:
dependency: "direct main"
description:
name: permission_handler
sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb"
url: "https://pub.dev"
source: hosted
version: "11.3.1"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474"
url: "https://pub.dev"
source: hosted
version: "12.0.5"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662
url: "https://pub.dev"
source: hosted
version: "9.4.4"
permission_handler_html:
dependency: transitive
description:
name: permission_handler_html
sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d"
url: "https://pub.dev"
source: hosted
version: "0.1.1"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20"
url: "https://pub.dev"
source: hosted
version: "4.2.1"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
url: "https://pub.dev"
source: hosted
version: "0.2.1"
petitparser:
dependency: transitive
description:
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -53,6 +53,7 @@ dependencies:
path_provider: ^2.1.1
open_file: ^3.3.2
home_widget: ^0.4.1
permission_handler: ^11.3.1

dependency_overrides:
# flutter compass in pub.dev is not updated

1 comment on commit 71d374e

@iqfareez
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example modal sheet popups:

Screenshot_1711642586
Screenshot_1711643209

Please sign in to comment.