Skip to content

Instantly share code, notes, and snippets.

@marcellogalhardo
Last active March 18, 2024 15:36
Show Gist options
  • Save marcellogalhardo/bbf43cf43a0eef980442ffde10ae2e54 to your computer and use it in GitHub Desktop.
Save marcellogalhardo/bbf43cf43a0eef980442ffde10ae2e54 to your computer and use it in GitHub Desktop.
A abstraction to handle permissions in a Compose-way.
import android.app.Activity
import android.content.pm.PackageManager
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalConfiguration
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
internal interface PermissionState {
val status: Status
fun requestPermission()
enum class Status { Granted, Denied, ShowRationale, NeverAskAgain }
}
internal fun PermissionState.shouldRequestPermission(): Boolean {
return status != Status.Granted && status != Status.NeverAskAgain
}
private class PermissionStateImpl(
private val activity: Activity,
private val permission: String,
) : PermissionState {
override var status: Status by mutableStateOf(
getPermissionStatus(isRequestPermissionsResult = false)
)
fun onResult() {
status = getPermissionStatus(isRequestPermissionsResult = true)
}
var launcher: ActivityResultLauncher<String>? = null
override fun requestPermission() {
launcher?.launch(permission)
}
private fun getPermissionStatus(
isRequestPermissionsResult: Boolean,
): Status = with(activity) {
when {
isPermissionGranted(permission) -> Status.Granted
shouldShowRationale(permission) -> Status.ShowRationale
isRequestPermissionsResult -> Status.NeverAskAgain
else -> Status.Denied
}
}
}
private fun Activity.isPermissionGranted(permission: String): Boolean {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
}
private fun Activity.shouldShowRationale(permission: String): Boolean {
return ActivityCompat.shouldShowRequestPermissionRationale(this, permission)
}
@Composable
internal fun rememberPermissionState(
permission: String,
): PermissionState {
val activity = LocalActivity.current
val handler = remember(LocalConfiguration.current) { PermissionStateImpl(activity, permission) }
handler.launcher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.RequestPermission(),
onResult = { handler.onResult() },
)
return handler
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment