From cf439e946411493d8917d42fc79f3ddddc795edc Mon Sep 17 00:00:00 2001 From: Yusuf Nasser Date: Fri, 27 Jun 2025 05:31:27 +0300 Subject: [PATCH] replace image persistent uri permission with persistent image storage --- .../category/component/CategorySheet.kt | 47 +++---------------- .../java/com/example/tudee/utils/SaveImage.kt | 39 +++++++++++++++ 2 files changed, 46 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/com/example/tudee/utils/SaveImage.kt diff --git a/app/src/main/java/com/example/tudee/presentation/screen/category/component/CategorySheet.kt b/app/src/main/java/com/example/tudee/presentation/screen/category/component/CategorySheet.kt index b14bf509..d918ca21 100644 --- a/app/src/main/java/com/example/tudee/presentation/screen/category/component/CategorySheet.kt +++ b/app/src/main/java/com/example/tudee/presentation/screen/category/component/CategorySheet.kt @@ -1,7 +1,6 @@ package com.example.tudee.presentation.screen.category.component import android.Manifest -import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.util.Log @@ -35,6 +34,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -62,6 +62,8 @@ import com.example.tudee.presentation.screen.category.model.CategorySheetMode import com.example.tudee.presentation.screen.category.model.CategorySheetState import com.example.tudee.presentation.screen.category.model.UiImage import com.example.tudee.presentation.screen.category.model.isNotNull +import com.example.tudee.utils.saveImageToInternalStorage +import kotlinx.coroutines.launch @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -115,39 +117,21 @@ private fun CategorySheetContent( } val context = LocalContext.current + val coroutineScope = rememberCoroutineScope() val photoPickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.PickVisualMedia() ) { uri -> uri?.let { - try { - context.contentResolver.takePersistableUriPermission( - uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION - ) - selectedUiImage = UiImage.External(it.toString()) - Log.d("IMAGE_PICKER", "Selected image URI: $uri") - } catch (e: Exception) { - Log.e("PERMISSION", "Error: ${e.message}") + coroutineScope.launch { + val tempUri = saveImageToInternalStorage(context, uri) + selectedUiImage = UiImage.External(tempUri.toString()) } } } - val permissionLauncher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.RequestPermission() - ) { isGranted -> - if (isGranted) { - photoPickerLauncher.launch( - PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly) - ) - } else { - Log.e("PERMISSION", "Storage permission denied") - } - } - val isFormValid = categoryName.isNotBlank() && selectedUiImage.isNotNull() - Column( modifier = Modifier .padding(horizontal = 16.dp) @@ -168,26 +152,9 @@ private fun CategorySheetContent( CategoryImageSection( selectedImage = selectedUiImage, onEditImage = { - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { - when { - ContextCompat.checkSelfPermission( - context, - Manifest.permission.READ_EXTERNAL_STORAGE - ) == PackageManager.PERMISSION_GRANTED -> { - photoPickerLauncher.launch( - PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly) - ) - } - - else -> { - permissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE) - } - } - } else { photoPickerLauncher.launch( PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly) ) - } } ) } diff --git a/app/src/main/java/com/example/tudee/utils/SaveImage.kt b/app/src/main/java/com/example/tudee/utils/SaveImage.kt new file mode 100644 index 00000000..7ab642ba --- /dev/null +++ b/app/src/main/java/com/example/tudee/utils/SaveImage.kt @@ -0,0 +1,39 @@ +package com.example.tudee.utils + +import android.content.Context +import android.net.Uri +import androidx.core.net.toUri +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import java.io.File +import java.io.FileOutputStream +import java.util.UUID + +/** + * Copies an image from a given content URI to the app's internal storage. + * + * @param context The application context. + * @param originalUri The content URI of the original image. + * @return The URI of the newly created copy, or null if it fails. + */ +suspend fun saveImageToInternalStorage(context: Context, originalUri: Uri): Uri? { + return withContext(Dispatchers.IO) { + try { + val inputStream = context.contentResolver.openInputStream(originalUri) + + val fileName = "copied_image_${UUID.randomUUID()}.jpg" + val file = File(context.filesDir, fileName) + val outputStream = FileOutputStream(file) + + inputStream?.copyTo(outputStream) + + inputStream?.close() + outputStream.close() + + file.toUri() + } catch (e: Exception) { + e.printStackTrace() + null + } + } +} \ No newline at end of file