Skip to content

Commit 65abfa5

Browse files
committed
Fix image selection starting from API 33 & screenshot deletion
1 parent b7c7ea1 commit 65abfa5

File tree

12 files changed

+66
-63
lines changed

12 files changed

+66
-63
lines changed

.idea/deploymentTargetSelector.xml

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/main/kotlin/com/w2sv/autocrop/activities/crop/CropFragment.kt

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.w2sv.autocrop.activities.crop
22

3-
import android.content.ContentResolver
43
import android.content.Context
54
import android.content.Intent
65
import android.net.Uri
@@ -64,13 +63,13 @@ class CropFragment
6463
private val _liveProgress = MutableLiveData(0)
6564

6665
suspend fun cropCoroutine(
67-
contentResolver: ContentResolver,
66+
context: Context,
6867
onFinishedListener: () -> Unit
6968
) {
7069
coroutineScope {
7170
getImminentUris().forEach { uri ->
7271
withContext(Dispatchers.IO) {
73-
attemptCropBundleCreation(uri, contentResolver)?.let {
72+
attemptCropBundleCreation(uri, context)?.let {
7473
cropBundles.add(it)
7574
}
7675
}
@@ -87,13 +86,13 @@ class CropFragment
8786
subList(liveProgress.value!!, size)
8887
}
8988

90-
private fun attemptCropBundleCreation(screenshotUri: Uri, contentResolver: ContentResolver): CropBundle? {
89+
private fun attemptCropBundleCreation(screenshotUri: Uri, context: Context): CropBundle? {
9190
i { "attemptCropBundleCreation; screenshotUri=$screenshotUri" }
9291

9392
return CropBundle.attemptCreation(
9493
screenshotMediaUri = screenshotUri,
9594
cropSensitivity = cropSensitivity.value,
96-
contentResolver = contentResolver
95+
context = context
9796
)
9897
.run {
9998
when (this) {
@@ -157,7 +156,7 @@ class CropFragment
157156
super.onResume()
158157

159158
lifecycleScope.launch {
160-
viewModel.cropCoroutine(requireContext().contentResolver) {
159+
viewModel.cropCoroutine(requireContext()) {
161160
invokeSubsequentScreen()
162161
}
163162
}

app/src/main/kotlin/com/w2sv/autocrop/activities/examination/ExaminationActivity.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import kotlinx.coroutines.Dispatchers
2222
import kotlinx.coroutines.Job
2323
import kotlinx.coroutines.flow.SharingStarted
2424
import kotlinx.coroutines.launch
25+
import slimber.log.i
2526
import javax.inject.Inject
2627

2728
@AndroidEntryPoint
@@ -30,7 +31,7 @@ class ExaminationActivity : ViewBoundFragmentActivity() {
3031
@HiltViewModel
3132
class ViewModel @Inject constructor(
3233
private val cropBundleIOProcessingUseCase: CropBundleIOProcessingUseCase,
33-
preferencesRepository: PreferencesRepository
34+
private val preferencesRepository: PreferencesRepository
3435
) : androidx.lifecycle.ViewModel() {
3536

3637
private val cropBundleIOResults = mutableListOf<CropBundleIOResult>()
@@ -58,18 +59,22 @@ class ExaminationActivity : ViewBoundFragmentActivity() {
5859
cropBundleIOResults.add(
5960
cropBundleIOProcessingUseCase.invoke(
6061
cropBitmap = cropBundle.crop.bitmap,
61-
screenshotMediaStoreData = cropBundle.screenshot.mediaStoreData,
62-
deleteScreenshot = deleteScreenshots.value,
62+
screenshot = cropBundle.screenshot,
63+
deleteScreenshot = deleteScreenshots.value.also { i { "Delete screnshot: $it" } },
6364
context = context
6465
)
6566
)
6667
}
6768

68-
private val deleteScreenshots = preferencesRepository.deleteScreenshots.stateIn(
69+
val deleteScreenshots = preferencesRepository.deleteScreenshots.stateIn(
6970
viewModelScope,
7071
SharingStarted.Eagerly
7172
)
7273

74+
fun toggleDeleteScreenshots() {
75+
viewModelScope.launch { preferencesRepository.deleteScreenshots.save(!deleteScreenshots.value) }
76+
}
77+
7378
fun navigateToMainActivity(activity: Activity) {
7479
MainActivity.start(
7580
activity = activity,

app/src/main/kotlin/com/w2sv/autocrop/activities/examination/pager/CropPagerFragment.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,6 @@ class CropPagerFragment :
9090
private val resources: Resources
9191
) : androidx.lifecycle.ViewModel() {
9292

93-
val deleteScreenshots = preferencesRepository.deleteScreenshots.stateIn(viewModelScope, SharingStarted.Eagerly)
94-
95-
fun saveDeleteScreenshots(value: Boolean) {
96-
viewModelScope.launch { preferencesRepository.deleteScreenshots.save(value) }
97-
}
98-
9993
val dataSet = CropPager.DataSet(ExaminationActivity.ViewModel.cropBundles)
10094

10195
// ==================
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.w2sv.autocrop.activities.examination.pager.dialogs.cropsaving
22

33
import androidx.appcompat.app.AlertDialog
4+
import androidx.fragment.app.activityViewModels
45
import androidx.fragment.app.viewModels
6+
import com.w2sv.autocrop.activities.examination.ExaminationActivity
57
import com.w2sv.autocrop.activities.examination.pager.CropPagerFragment
68
import com.w2sv.autocrop.ui.views.RoundedDialogFragment
79

@@ -11,14 +13,14 @@ abstract class AbstractCropSavingDialogFragment : RoundedDialogFragment() {
1113
const val EXTRA_SHOW_DISCARD_BUTTON = "com.w2sv.autocrop.extra.SHOW_DISMISS_BUTTON"
1214
}
1315

14-
private val viewModel by viewModels<CropPagerFragment.ViewModel>({ requireParentFragment() })
16+
private val viewModel by activityViewModels<ExaminationActivity.ViewModel>()
1517

1618
protected fun AlertDialog.Builder.setDeleteCorrespondingScreenshotsOption(text: String) {
1719
setMultiChoiceItems(
1820
arrayOf(text),
1921
booleanArrayOf(viewModel.deleteScreenshots.value)
2022
) { _, _, _ ->
21-
viewModel.saveDeleteScreenshots(!viewModel.deleteScreenshots.value)
23+
viewModel.toggleDeleteScreenshots()
2224
}
2325
}
2426
}

app/src/main/kotlin/com/w2sv/autocrop/activities/main/flowfield/FlowFieldFragment.kt

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -279,23 +279,14 @@ class FlowFieldFragment :
279279
},
280280
callbackFromQ = { uris ->
281281
if (uris.isNotEmpty()) {
282-
@SuppressLint("NewApi")
283-
if (getMediaUri(context = requireContext(), uri = uris.first()) == null) {
284-
requireContext().showToast(
285-
R.string.content_provider_not_supported_please_select_a_different_one,
286-
Toast.LENGTH_LONG
282+
// Take persistable read permission for each Uri; Fixes consecutively occasionally occurring permission exception on reading in bitmap
283+
uris.forEach {
284+
requireContext().contentResolver.takePersistableUriPermission(
285+
it,
286+
Intent.FLAG_GRANT_READ_URI_PERMISSION
287287
)
288288
}
289-
else {
290-
// Take persistable read permission for each Uri; Fixes consecutively occasionally occurring permission exception on reading in bitmap
291-
uris.forEach {
292-
requireContext().contentResolver.takePersistableUriPermission(
293-
it,
294-
Intent.FLAG_GRANT_READ_URI_PERMISSION
295-
)
296-
}
297-
navigateToCropActivity(uris)
298-
}
289+
navigateToCropActivity(uris)
299290
}
300291
}
301292
)

core/cropbundle/src/main/kotlin/com/w2sv/cropbundle/CropBundle.kt

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.w2sv.cropbundle
22

33
import android.content.ContentResolver
4+
import android.content.Context
45
import android.graphics.Bitmap
56
import android.net.Uri
67
import android.os.Parcelable
@@ -45,9 +46,9 @@ data class CropBundle(
4546
fun attemptCreation(
4647
screenshotMediaUri: Uri,
4748
@CropSensitivity cropSensitivity: Int,
48-
contentResolver: ContentResolver
49+
context: Context
4950
): CreationResult =
50-
when (val screenshotBitmap = contentResolver.loadBitmap(screenshotMediaUri)) {
51+
when (val screenshotBitmap = context.contentResolver.loadBitmap(screenshotMediaUri)) {
5152
null -> CreationResult.Failure.BitmapLoadingFailed
5253
else -> {
5354
when (val cropResult = screenshotBitmap.crop(cropSensitivity)) {
@@ -57,7 +58,7 @@ data class CropBundle(
5758
uri = screenshotMediaUri,
5859
height = screenshotBitmap.height,
5960
mediaStoreData = Screenshot.MediaStoreData.query(
60-
contentResolver,
61+
context,
6162
screenshotMediaUri
6263
)
6364
)
@@ -92,13 +93,14 @@ data class Screenshot(
9293
val diskUsage: Long,
9394
val fileName: String,
9495
val mimeType: ImageMimeType,
95-
val id: Long
96+
val id: Long? // null upon no photo picker available, which leads to uri being a document uri
9697
) : Parcelable {
9798

9899
companion object {
99-
fun query(contentResolver: ContentResolver, uri: Uri): MediaStoreData {
100+
fun query(context: Context, uri: Uri): MediaStoreData {
100101
i { "uri: $uri" } // content://media/picker/0/com.android.providers.media.photopicker/media/1000016069
101-
return contentResolver.queryMediaStoreData(
102+
// // content://com.android.providers.media.documents/document/image%3A33
103+
return context.contentResolver.queryMediaStoreData(
102104
uri = uri,
103105
columns = arrayOf(
104106
MediaStore.Images.Media.SIZE,
@@ -111,7 +113,7 @@ data class Screenshot(
111113
diskUsage = it.getLong(it.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)),
112114
fileName = fileName,
113115
mimeType = ImageMimeType.parse(it.getString(it.getColumnIndexOrThrow(MediaStore.Images.Media.MIME_TYPE))),
114-
id = fileName.substringBeforeLast(".").toLong() // TODO: probably still unreliable
116+
id = fileName.substringBeforeLast(".").toLongOrNull() // TODO: probably still unreliable
115117
)
116118
.also { i { it.toString() } }
117119
}

core/cropbundle/src/main/kotlin/com/w2sv/cropbundle/io/CropBundleIOProcessingUseCase.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,34 @@ import android.content.Context
44
import android.graphics.Bitmap
55
import com.w2sv.cropbundle.Screenshot
66
import com.w2sv.domain.repository.PreferencesRepository
7+
import slimber.log.i
78
import javax.inject.Inject
89

910
class CropBundleIOProcessingUseCase @Inject constructor(
1011
private val preferencesRepository: PreferencesRepository
1112
) {
1213
fun invoke(
1314
cropBitmap: Bitmap,
14-
screenshotMediaStoreData: Screenshot.MediaStoreData,
15+
screenshot: Screenshot,
1516
deleteScreenshot: Boolean,
1617
context: Context
1718
): CropBundleIOResult =
1819
CropBundleIOResult(
1920
cropFileUri = context.contentResolver.saveBitmap(
2021
bitmap = cropBitmap,
21-
mimeType = screenshotMediaStoreData.mimeType,
22+
mimeType = screenshot.mediaStoreData.mimeType,
2223
fileName = cropFileName(
23-
fileName = screenshotMediaStoreData.fileName,
24-
mimeType = screenshotMediaStoreData.mimeType
24+
fileName = screenshot.mediaStoreData.fileName,
25+
mimeType = screenshot.mediaStoreData.mimeType
2526
),
2627
parentDocumentUri = preferencesRepository.getWritableCropSaveDirDocumentUriOrNull(context)
2728
),
2829
screenshotDeletionResult = if (deleteScreenshot) {
2930
ScreenshotDeletionResult.get(
30-
mediaStoreId = screenshotMediaStoreData.id,
31+
screenshot = screenshot,
3132
contentResolver = context.contentResolver
3233
)
34+
.also { i { "Screenshot deletion result: $it" } }
3335
}
3436
else {
3537
null

core/cropbundle/src/main/kotlin/com/w2sv/cropbundle/io/ImageDeletion.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@ fun getImageContentUri(mediaStoreId: Long): Uri =
1313
)
1414

1515
@ChecksSdkIntAtLeast(api=Build.VERSION_CODES.R)
16-
val IMAGE_DELETION_REQUIRING_APPROVAL: Boolean =
16+
val mediaDeletionRequiresExplicitUserApproval: Boolean =
1717
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R

0 commit comments

Comments
 (0)