Skip to content

Commit

Permalink
Merge pull request #107 from Joe3112/feature/notifications
Browse files Browse the repository at this point in the history
Add local notification permission
  • Loading branch information
MohamedRejeb committed Jul 2, 2024
2 parents 3818a28 + 7f350e9 commit de4e950
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 37 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.mohamedrejeb.calf.permissions

import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
Expand Down Expand Up @@ -101,31 +102,37 @@ internal fun Activity.shouldShowRationale(permission: String): Boolean {

internal fun Permission.toAndroidPermission(): String {
return when (this) {
Permission.Call -> android.Manifest.permission.CALL_PHONE
Permission.Camera -> android.Manifest.permission.CAMERA
Permission.Gallery -> android.Manifest.permission.READ_EXTERNAL_STORAGE
Permission.ReadStorage -> android.Manifest.permission.READ_EXTERNAL_STORAGE
Permission.WriteStorage -> android.Manifest.permission.WRITE_EXTERNAL_STORAGE
Permission.FineLocation -> android.Manifest.permission.ACCESS_FINE_LOCATION
Permission.CoarseLocation -> android.Manifest.permission.ACCESS_COARSE_LOCATION
Permission.RemoteNotification -> android.Manifest.permission.RECEIVE_BOOT_COMPLETED
Permission.RecordAudio -> android.Manifest.permission.RECORD_AUDIO
Permission.BluetoothLe -> android.Manifest.permission.BLUETOOTH
Permission.Call -> Manifest.permission.CALL_PHONE
Permission.Camera -> Manifest.permission.CAMERA
Permission.Gallery -> Manifest.permission.READ_EXTERNAL_STORAGE
Permission.ReadStorage -> Manifest.permission.READ_EXTERNAL_STORAGE
Permission.WriteStorage -> Manifest.permission.WRITE_EXTERNAL_STORAGE
Permission.FineLocation -> Manifest.permission.ACCESS_FINE_LOCATION
Permission.CoarseLocation -> Manifest.permission.ACCESS_COARSE_LOCATION
Permission.RemoteNotification -> Manifest.permission.RECEIVE_BOOT_COMPLETED
Permission.RecordAudio -> Manifest.permission.RECORD_AUDIO
Permission.BluetoothLe -> Manifest.permission.BLUETOOTH
Permission.BluetoothScan ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
android.Manifest.permission.BLUETOOTH_SCAN
Manifest.permission.BLUETOOTH_SCAN
} else {
""
}
Permission.BluetoothConnect ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
android.Manifest.permission.BLUETOOTH_CONNECT
Manifest.permission.BLUETOOTH_CONNECT
} else {
""
}
Permission.BluetoothAdvertise ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
android.Manifest.permission.BLUETOOTH_ADVERTISE
Manifest.permission.BLUETOOTH_ADVERTISE
} else {
""
}
Permission.Notification ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Manifest.permission.POST_NOTIFICATIONS
} else {
""
}
Expand All @@ -150,6 +157,7 @@ internal fun getPermissionFromAndroidPermission(androidPermission: String): Perm
android.Manifest.permission.WRITE_EXTERNAL_STORAGE -> Permission.WriteStorage
android.Manifest.permission.ACCESS_FINE_LOCATION -> Permission.FineLocation
android.Manifest.permission.ACCESS_COARSE_LOCATION -> Permission.CoarseLocation
android.Manifest.permission.POST_NOTIFICATIONS -> Permission.Notification
android.Manifest.permission.RECEIVE_BOOT_COMPLETED -> Permission.RemoteNotification
android.Manifest.permission.RECORD_AUDIO -> Permission.RecordAudio
android.Manifest.permission.BLUETOOTH -> Permission.BluetoothLe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ enum class Permission {
WriteStorage,
FineLocation,
CoarseLocation,
Notification,
RemoteNotification,
RecordAudio,
BluetoothLe,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.mohamedrejeb.calf.permissions.helper.AVCapturePermissionHelper
import com.mohamedrejeb.calf.permissions.helper.BluetoothPermissionHelper
import com.mohamedrejeb.calf.permissions.helper.GalleryPermissionHelper
import com.mohamedrejeb.calf.permissions.helper.GrantedPermissionHelper
import com.mohamedrejeb.calf.permissions.helper.LocalNotificationPermissionHelper
import com.mohamedrejeb.calf.permissions.helper.LocationPermissionHelper
import com.mohamedrejeb.calf.permissions.helper.PermissionHelper
import com.mohamedrejeb.calf.permissions.helper.RemoteNotificationPermissionHelper
Expand All @@ -16,10 +17,12 @@ internal fun Permission.getPermissionDelegate(): PermissionHelper {
Permission.Gallery -> GalleryPermissionHelper()
Permission.ReadStorage, Permission.WriteStorage, Permission.Call -> GrantedPermissionHelper()
Permission.FineLocation, Permission.CoarseLocation -> LocationPermissionHelper()
Permission.Notification -> LocalNotificationPermissionHelper()
Permission.RemoteNotification -> RemoteNotificationPermissionHelper()
Permission.RecordAudio -> AVCapturePermissionHelper(AVMediaTypeAudio)
Permission.BluetoothLe, Permission.BluetoothScan,
Permission.BluetoothConnect, Permission.BluetoothAdvertise,
-> BluetoothPermissionHelper()

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.mohamedrejeb.calf.permissions.helper

import com.mohamedrejeb.calf.permissions.ExperimentalPermissionsApi
import com.mohamedrejeb.calf.permissions.PermissionStatus
import platform.UserNotifications.UNAuthorizationOptionAlert
import platform.UserNotifications.UNAuthorizationOptionBadge
import platform.UserNotifications.UNAuthorizationOptionSound
import platform.UserNotifications.UNAuthorizationStatusAuthorized
import platform.UserNotifications.UNAuthorizationStatusEphemeral
import platform.UserNotifications.UNAuthorizationStatusNotDetermined
import platform.UserNotifications.UNAuthorizationStatusProvisional
import platform.UserNotifications.UNUserNotificationCenter

internal class LocalNotificationPermissionHelper : PermissionHelper {

override fun launchPermissionRequest(onPermissionResult: (Boolean) -> Unit) {
val notificationCenter = UNUserNotificationCenter.currentNotificationCenter()

notificationCenter.getNotificationSettingsWithCompletionHandler { settings ->
when (settings?.authorizationStatus) {
UNAuthorizationStatusAuthorized,
UNAuthorizationStatusProvisional,
UNAuthorizationStatusEphemeral -> onPermissionResult(true)
UNAuthorizationStatusNotDetermined -> {
notificationCenter.requestAuthorizationWithOptions(
UNAuthorizationOptionSound.or(UNAuthorizationOptionAlert).or(UNAuthorizationOptionBadge)
) { isOk, error ->
if (isOk && error == null) {
onPermissionResult(true)
} else {
onPermissionResult(false)
}
}
}
else -> onPermissionResult(false)
}
}
}

@ExperimentalPermissionsApi
override fun getPermissionStatus(onPermissionResult: (PermissionStatus) -> Unit) {
val notificationCenter = UNUserNotificationCenter.currentNotificationCenter()
notificationCenter.getNotificationSettingsWithCompletionHandler { settings ->
when (settings?.authorizationStatus) {
UNAuthorizationStatusAuthorized,
UNAuthorizationStatusProvisional,
UNAuthorizationStatusEphemeral -> onPermissionResult(PermissionStatus.Granted)
else -> onPermissionResult(PermissionStatus.Denied(false))
}
}
}
}
24 changes: 24 additions & 0 deletions docs/permissions.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,27 @@ On iOS you need to add the following key to your `Info.plist` file:
```

The string value is the message that will be displayed to the user when the permission is requested.

### Post Notifications Permission

To request the post notifications permission, use `Permission.Notification`.

#### Android

On Android API version 33 and up, you need to add the following permission to your `AndroidManifest.xml` file:

```xml
<!-- For Posting Notifications -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
```

#### iOS

On iOS you need to add the following key to your `Info.plist` file:

```xml
<key>NSUserNotificationsUsageDescription</key>
<string>Notifications permission is required to show notifications</string>
```

The string value is the message that will be displayed to the user when the permission is requested.
1 change: 1 addition & 0 deletions sample/android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<application
android:allowBackup="false"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,32 @@ import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.mohamedrejeb.calf.permissions.ExperimentalPermissionsApi
import com.mohamedrejeb.calf.permissions.Permission
import com.mohamedrejeb.calf.permissions.isGranted
import com.mohamedrejeb.calf.permissions.rememberPermissionState
import com.mohamedrejeb.calf.permissions.shouldShowRationale

@Composable
fun PermissionScreen(navigateBack: () -> Unit) {
Box(
modifier =
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.windowInsetsPadding(WindowInsets.systemBars)
.windowInsetsPadding(WindowInsets.ime),
Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background)
.windowInsetsPadding(WindowInsets.systemBars)
.windowInsetsPadding(WindowInsets.ime),
) {
LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally,
modifier =
Modifier
.fillMaxSize()
.padding(16.dp),
Modifier
.fillMaxSize()
.padding(16.dp),
) {
items(Permission.entries) { permission ->
PermissionItem(permission = permission)
Expand All @@ -57,14 +59,14 @@ fun PermissionScreen(navigateBack: () -> Unit) {
navigateBack()
},
colors =
IconButtonDefaults.iconButtonColors(
contentColor = MaterialTheme.colorScheme.onBackground,
containerColor = MaterialTheme.colorScheme.surface,
),
IconButtonDefaults.iconButtonColors(
contentColor = MaterialTheme.colorScheme.onBackground,
containerColor = MaterialTheme.colorScheme.surface,
),
modifier =
Modifier
.align(Alignment.TopStart)
.padding(16.dp),
Modifier
.align(Alignment.TopStart)
.padding(16.dp),
) {
Icon(
Icons.Filled.ArrowBackIosNew,
Expand All @@ -90,6 +92,13 @@ private fun PermissionItem(permission: Permission) {
text = "Is permission granted: ${permissionState.status.isGranted}",
)

LaunchedEffect(permissionState.status) {
println("${permission.name}: ${permissionState.status}")
if (!permissionState.status.isGranted && permissionState.status.shouldShowRationale) {
println("${permission.name}: Show Rationale")
}
}

Button(
onClick = {
println("Click")
Expand Down
20 changes: 11 additions & 9 deletions sample/ios/Calf/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>NSUserNotificationsUsageDescription</key>
<string>Just for tests</string>
<key>NSCameraUsageDescription</key>
<string>Just for tests</string>
<string>Just for tests</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Just for tests</string>
<string>Just for tests</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Just for tests</string>
<key>NSMicrophoneUsageDescription</key>
<string>Just for tests</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Just for tests</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Just for tests</string>
<string>Just for tests</string>
<key>NSMicrophoneUsageDescription</key>
<string>Just for tests</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Just for tests</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Just for tests</string>
</dict>
</plist>

0 comments on commit de4e950

Please sign in to comment.