I want to enable the user to take a photo using the camera, actually, it is something that is done everywhere and is not very difficult, but I could not do some of it here. If the user gives permission, everything works fine, I can take pictures with the camera, but if the user does not allow it, the permission request popup does not appear. If the user does not let it, I want the popup to appear until they enable it. It's supposed to be like this anyway. am I wrong? My codes are like this
I follow this documentation in medium :
TakePhotoScreen
@Composable
fun TakePhotoScreenRoute(
navHostController: NavHostController,
sharedViewModel: SharedViewModel,
viewModel: TakePhotoViewModel = hiltViewModel()
) {
val state by viewModel.state.collectAsState()
TakePhotoScreen(
navHostController = navHostController,
sharedViewModel = sharedViewModel,
createImageFile = viewModel::createImageFile,
saveUserImgToDataStore = viewModel::saveUserImgToDataStore,
requestCameraPermission = viewModel::requestCameraPermission,
state = state
)
}
@Composable
fun TakePhotoScreen(
navHostController: NavHostController,
sharedViewModel: SharedViewModel,
createImageFile: (Context) -> File,
saveUserImgToDataStore: (String) -> Unit,
requestCameraPermission: (ActivityResultLauncher<String>) -> Unit,
state: TakePhotoScreenState
) {
val context = LocalContext.current
val file = createImageFile(context)
val uri = FileProvider.getUriForFile(
Objects.requireNonNull(context),
BuildConfig.APPLICATION_ID + ".provider", file
)
var capturedImageUri by remember {
mutableStateOf<Uri>(Uri.EMPTY)
}
val cameraLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.TakePicture()) {
capturedImageUri = uri
}
val permissionLauncher = rememberLauncherForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
cameraLauncher.launch(uri)
} else {
Toast.makeText(context, "Fotoğraf çekmek için Kamera iznine ihtiyaç var.", Toast.LENGTH_SHORT).show()
//navHostController.navigate(DashBoardScreen.ProfileScreen.route)
}
}
Column(
Modifier
.fillMaxSize()
.padding(10.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(
onClick = {
val permissionCheckResult =
ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
if (permissionCheckResult == PackageManager.PERMISSION_GRANTED) {
cameraLauncher.launch(uri)
} else {
// Request a permission
permissionLauncher.launch(Manifest.permission.CAMERA)
}
}) {
Text(text = "Capture Image From Camera")
}
}
var navigate by remember { mutableStateOf(true) }
if (capturedImageUri.path?.isNotEmpty() == true && navigate) {
saveUserImgToDataStore(capturedImageUri.toString())
//sharedViewModel.onChangeUserImage(capturedImageUri.toString())
navHostController.navigate(DashBoardScreen.ProfileScreen.route)
navigate = false
}
}
TakePhotoViewModel
@HiltViewModel
class TakePhotoViewModel @Inject constructor(
private val dataStore: PreferenceDataStoreHelper
): ViewModel() {
private val _state = MutableStateFlow(TakePhotoScreenState())
val state: StateFlow<TakePhotoScreenState> = _state.asStateFlow()
fun saveUserImgToDataStore(userAvatar: String) {
viewModelScope.launch {
dataStore.putPreference(PreferenceDataStoreConstants.USER_IMG,userAvatar)
}
}
fun requestCameraPermission(permissionLauncher: ActivityResultLauncher<String>) {
permissionLauncher.launch(Manifest.permission.CAMERA)
}
fun createImageFile(context: Context): File {
val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(Date())
val imageFileName = "JPEG_$timeStamp.jpg"
val image = File(context.externalCacheDir, imageFileName)
return image
}
}
data class TakePhotoScreenState(
val imgFile: File? = null
)
In TakePhotoScren, when a button is clicked, it asks for permission for the camera, I want to remove this button and when the user comes to this screen, the permission request popup will appear and the camera will come. I tried to do it like this
...
val permissionCheckResult =
ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
if (permissionCheckResult == PackageManager.PERMISSION_GRANTED) {
cameraLauncher.launch(uri)
} else {
// Request a permission
permissionLauncher.launch(Manifest.permission.CAMERA)
}
/* Button(
onClick = {
val permissionCheckResult =
ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
if (permissionCheckResult == PackageManager.PERMISSION_GRANTED) {
cameraLauncher.launch(uri)
} else {
// Request a permission
permissionLauncher.launch(Manifest.permission.CAMERA)
}
}) {
Text(text = "Capture Image From Camera")
} */
...
But I get this error
java.lang.IllegalStateException: Launcher has not been initialized
Your app should respect the user's decision to deny a permission. Starting in Android 11 (API level 30), if the user taps Deny for a specific permission more than once during your app's lifetime of installation on a device, the user doesn't see the system permissions dialog if your app requests that permission again.
As described in: https://developer.android.com/training/permissions/requesting#handle-denial
In this scenario you must either navigate the user to the app settings to change it or simply show them that they cannot use this feature.