Skip to content

Commit 3cf14aa

Browse files
committed
Integrate crop sharing
1 parent 45c5175 commit 3cf14aa

File tree

13 files changed

+127
-65
lines changed

13 files changed

+127
-65
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.autocrop.activities
2+
3+
object IntentExtraIdentifier {
4+
val SELECTED_IMAGE_URIS = intentExtraIdentifier("selected_image_uri_strings")
5+
val N_DISMISSED_IMAGES = intentExtraIdentifier("n_dismissed_images")
6+
7+
val N_SAVED_CROPS_WITH_N_DELETED_SCREENSHOTS = intentExtraIdentifier("n_saved_crops")
8+
val CROP_WRITE_DIR_PATH = intentExtraIdentifier("crop_write_dir_path")
9+
val CROP_WRITE_URIS = intentExtraIdentifier("crop_write_uris")
10+
11+
private fun intentExtraIdentifier(name: String): String = "com.autocrop.$name"
12+
}

app/src/main/java/com/autocrop/activities/IntentIdentifier.kt

Lines changed: 0 additions & 10 deletions
This file was deleted.

app/src/main/java/com/autocrop/activities/cropping/CroppingActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package com.autocrop.activities.cropping
33
import android.content.Intent
44
import androidx.lifecycle.ViewModelProvider
55
import com.autocrop.activities.ActivityTransitions
6-
import com.autocrop.activities.IntentIdentifier
6+
import com.autocrop.activities.IntentExtraIdentifier
77
import com.autocrop.activities.cropping.fragments.cropping.CroppingFragment
88
import com.autocrop.activities.cropping.fragments.croppingfailed.CroppingFailedFragment
99
import com.autocrop.activities.main.MainActivity
@@ -27,7 +27,7 @@ class CroppingActivity :
2727
ViewModelProvider(
2828
this,
2929
CroppingActivityViewModelFactory(
30-
uris = intent.getParcelableArrayListExtra(IntentIdentifier.SELECTED_IMAGE_URIS)!!
30+
uris = intent.getParcelableArrayListExtra(IntentExtraIdentifier.SELECTED_IMAGE_URIS)!!
3131
)
3232
)[CroppingActivityViewModel::class.java]
3333

app/src/main/java/com/autocrop/activities/cropping/fragments/cropping/CroppingFragment.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import android.os.Looper
88
import android.view.View
99
import androidx.lifecycle.lifecycleScope
1010
import com.autocrop.activities.ActivityTransitions
11-
import com.autocrop.activities.IntentIdentifier
11+
import com.autocrop.activities.IntentExtraIdentifier
1212
import com.autocrop.activities.cropping.fragments.CroppingActivityFragment
1313
import com.autocrop.activities.examination.ExaminationActivity
1414
import com.autocrop.activities.examination.ExaminationActivityViewModel
@@ -84,7 +84,7 @@ class CroppingFragment
8484
requireActivity().let { activity ->
8585
startActivity(
8686
Intent(activity, ExaminationActivity::class.java).putExtra(
87-
IntentIdentifier.N_DISMISSED_IMAGES,
87+
IntentExtraIdentifier.N_DISMISSED_IMAGES,
8888
sharedViewModel.nDismissedImages
8989
)
9090
)

app/src/main/java/com/autocrop/activities/examination/ExaminationActivity.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import android.content.Intent
44
import androidx.fragment.app.Fragment
55
import androidx.lifecycle.ViewModelProvider
66
import com.autocrop.activities.ActivityTransitions
7-
import com.autocrop.activities.IntentIdentifier
7+
import com.autocrop.activities.IntentExtraIdentifier
88
import com.autocrop.activities.examination.fragments.apptitle.AppTitleFragment
99
import com.autocrop.activities.examination.fragments.saveall.SaveAllFragment
1010
import com.autocrop.activities.examination.fragments.sreenshotdeletionquery.ScreenshotDeletionQueryFragment
@@ -95,17 +95,22 @@ class ExaminationActivity :
9595
)
9696
.apply {
9797
putExtra(
98-
IntentIdentifier.N_SAVED_CROPS_WITH_N_DELETED_SCREENSHOTS,
98+
IntentExtraIdentifier.N_SAVED_CROPS_WITH_N_DELETED_SCREENSHOTS,
9999
intArrayOf(
100100
sharedViewModel.nSavedCrops,
101101
sharedViewModel.nDeletedScreenshots
102102
)
103103
)
104104
if (sharedViewModel.nSavedCrops != 0)
105105
putExtra(
106-
IntentIdentifier.CROP_WRITE_DIR_PATH,
106+
IntentExtraIdentifier.CROP_WRITE_DIR_PATH,
107107
sharedViewModel.cropWriteDirIdentifier()
108108
)
109+
if (sharedViewModel.cropWriteUris.isNotEmpty())
110+
putParcelableArrayListExtra(
111+
IntentExtraIdentifier.CROP_WRITE_URIS,
112+
ArrayList(sharedViewModel.cropWriteUris)
113+
)
109114
}
110115
)
111116
ActivityTransitions.RETURN(this)

app/src/main/java/com/autocrop/activities/examination/ExaminationActivityViewModel.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,18 @@ class ExaminationActivityViewModel(private val validSaveDirDocumentUri: Uri?)
2222
get() = _nDeletedScreenshots
2323
private var _nDeletedScreenshots = 0
2424

25+
val cropWriteUris = mutableListOf<Uri>()
26+
2527
fun processCropBundle(cropBundlesPosition: Int, deleteScreenshot: Boolean, context: Context){
26-
val (_, deletionResult) = context.processCropBundle(
28+
val (savingResult, deletionResult) = context.processCropBundle(
2729
cropBundles[cropBundlesPosition],
2830
validSaveDirDocumentUri,
2931
deleteScreenshot
3032
)
33+
with(savingResult){
34+
if (first)
35+
cropWriteUris.add(second)
36+
}
3137
deletionResult?.second?.let {
3238
deletionQueryScreenshotUris.add(it)
3339
Timber.i("Added $it to deletionQueryScreenshotUris")

app/src/main/java/com/autocrop/activities/examination/ImageFileIO.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import timber.log.Timber
2323
* second=!null -> first = false
2424
*/
2525
typealias DeletionResult = Pair<Boolean, Uri?>
26+
typealias SavingResult = Pair<Boolean, Uri>
2627

2728
/**
2829
* Saves [CropBundle.crop] under [cropFileName] depending on [CropBundle.screenshotUri]
@@ -31,9 +32,9 @@ typealias DeletionResult = Pair<Boolean, Uri?>
3132
fun Context.processCropBundle(
3233
cropBundle: CropBundle,
3334
validSaveDirDocumentUri: Uri?,
34-
deleteScreenshot: Boolean): Pair<Boolean, DeletionResult?>{
35+
deleteScreenshot: Boolean): Pair<SavingResult, DeletionResult?>{
3536

36-
val cropSuccessfullySaved = contentResolver.saveBitmap(
37+
val cropSavingResult = contentResolver.saveBitmap(
3738
cropBundle.crop,
3839
cropFileName(cropBundle.screenshotUri.fileName),
3940
validSaveDirDocumentUri
@@ -43,7 +44,7 @@ fun Context.processCropBundle(
4344
else
4445
null
4546

46-
return cropSuccessfullySaved to screenshotDeletionResult
47+
return cropSavingResult to screenshotDeletionResult
4748
}
4849

4950
//$$$$$$$$$$$$$$

app/src/main/java/com/autocrop/activities/examination/fragments/viewpager/ViewPagerFragment.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import android.view.View
66
import androidx.core.text.bold
77
import androidx.core.text.color
88
import androidx.lifecycle.ViewModelProvider
9-
import com.autocrop.activities.IntentIdentifier
9+
import com.autocrop.activities.IntentExtraIdentifier
1010
import com.autocrop.activities.examination.fragments.ExaminationActivityFragment
1111
import com.autocrop.activities.examination.fragments.viewpager.dialogs.DiscardAllConfirmationDialog
1212
import com.autocrop.activities.examination.fragments.viewpager.dialogs.SaveAllConfirmationDialog
@@ -48,7 +48,7 @@ class ViewPagerFragment:
4848
displayActivityEntrySnackbar()
4949
}
5050

51-
private val nDismissedImagesRetriever = IntentExtraRetriever<Int>(IntentIdentifier.N_DISMISSED_IMAGES)
51+
private val nDismissedImagesRetriever = IntentExtraRetriever<Int>(IntentExtraIdentifier.N_DISMISSED_IMAGES)
5252

5353
override fun displayActivityEntrySnackbar(){
5454
nDismissedImagesRetriever(requireActivity().intent, 0) ?.let {

app/src/main/java/com/autocrop/activities/main/fragments/flowfield/FlowFieldFragment.kt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import android.text.SpannableStringBuilder
1010
import android.view.View
1111
import androidx.activity.result.contract.ActivityResultContracts
1212
import androidx.core.text.color
13-
import com.autocrop.activities.IntentIdentifier
13+
import com.autocrop.activities.IntentExtraIdentifier
1414
import com.autocrop.activities.cropping.CroppingActivity
1515
import com.autocrop.activities.main.fragments.MainActivityFragment
1616
import com.autocrop.global.CropFileSaveDestinationPreferences
1717
import com.autocrop.uicontroller.fragment.ActivityRootFragment
18+
import com.autocrop.uielements.view.show
1819
import com.autocrop.utils.android.*
1920
import com.autocrop.utils.numericallyInflected
2021
import com.w2sv.autocrop.R
@@ -41,13 +42,34 @@ class FlowFieldFragment:
4142
setMenuInflationButtonOnClickListener()
4243
flowFieldBinding.setCaptureButton(binding.flowfieldCaptureButton, permissionsHandler)
4344

45+
requireActivity().intent.extras?.getParcelableArrayList<Uri>(IntentExtraIdentifier.CROP_WRITE_URIS)?.let {
46+
setCropSharingButton(it)
47+
}
48+
4449
// display CropIOResultSnackbar
4550
if (savedInstanceState == null)
4651
displayActivityEntrySnackbar()
4752
}
4853

49-
private val nSavedCropsRetriever = IntentExtraRetriever<IntArray>(IntentIdentifier.N_SAVED_CROPS_WITH_N_DELETED_SCREENSHOTS)
50-
private val cropWriteDirPathRetriever = IntentExtraRetriever<String>(IntentIdentifier.CROP_WRITE_DIR_PATH)
54+
private fun setCropSharingButton(cropWriteUris: ArrayList<Uri>){
55+
with(binding.cropSharingButton){
56+
show()
57+
setOnClickListener {
58+
startActivity(
59+
Intent.createChooser(Intent().apply {
60+
action = Intent.ACTION_SEND_MULTIPLE
61+
putParcelableArrayListExtra(Intent.EXTRA_STREAM, cropWriteUris)
62+
type = MimeTypes.IMAGE
63+
},
64+
"Share crops"
65+
)
66+
)
67+
}
68+
}
69+
}
70+
71+
private val nSavedCropsRetriever = IntentExtraRetriever<IntArray>(IntentExtraIdentifier.N_SAVED_CROPS_WITH_N_DELETED_SCREENSHOTS)
72+
private val cropWriteDirPathRetriever = IntentExtraRetriever<String>(IntentExtraIdentifier.CROP_WRITE_DIR_PATH)
5173

5274
override fun displayActivityEntrySnackbar(){
5375
nSavedCropsRetriever(requireActivity().intent)?.let {
@@ -162,7 +184,7 @@ class FlowFieldFragment:
162184
CroppingActivity::class.java
163185
)
164186
.putParcelableArrayListExtra(
165-
IntentIdentifier.SELECTED_IMAGE_URIS,
187+
IntentExtraIdentifier.SELECTED_IMAGE_URIS,
166188
ArrayList(data?.clipDataItems()!!.map { it.uri })
167189
)
168190
)

app/src/main/java/com/autocrop/utils/android/ImageFileIO.kt

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,44 +31,45 @@ val externalPicturesDir: File = Environment.getExternalStoragePublicDirectory(En
3131
* https://stackoverflow.com/a/10124040
3232
* https://stackoverflow.com/a/59536115
3333
*/
34-
fun ContentResolver.saveBitmap(bitmap: Bitmap, fileName: String, parentDocumentUri: Uri? = null): Boolean =
35-
bitmap.compressToStream(
36-
when {
37-
parentDocumentUri != null -> GetOutputStream.fromParentDocument(fileName, this, parentDocumentUri)
38-
apiNotNewerThanQ -> GetOutputStream.untilQ(fileName)
39-
else -> GetOutputStream.postQ(fileName, this)
40-
}
41-
)
34+
fun ContentResolver.saveBitmap(bitmap: Bitmap, fileName: String, parentDocumentUri: Uri? = null): Pair<Boolean, Uri>{
35+
val (outputStream, writeUri) = when {
36+
parentDocumentUri != null -> GetOutputStream.fromParentDocument(fileName, this, parentDocumentUri)
37+
apiNotNewerThanQ -> GetOutputStream.untilQ(fileName)
38+
else -> GetOutputStream.postQ(fileName, this)
39+
}
40+
41+
return (bitmap.compressToStream(outputStream) to writeUri)
4242
.also {
4343
Timber.i(
44-
if (it) "Successfully wrote $fileName" else "Couldn't write $fileName"
44+
if (it.first) "Successfully wrote $fileName" else "Couldn't write $fileName"
4545
)
4646
}
47+
}
4748

4849
fun Bitmap.compressToStream(stream: OutputStream) =
4950
compress(Bitmap.CompressFormat.JPEG, 100, stream)
5051
.also {stream.close()}
5152

5253
private object GetOutputStream{
53-
fun fromParentDocument(fileName: String, contentResolver: ContentResolver, parentDocumentUri: Uri): OutputStream = logBeforehand("GetOutputStream.fromParentDocument") {
54+
fun fromParentDocument(fileName: String, contentResolver: ContentResolver, parentDocumentUri: Uri): Pair<OutputStream, Uri> = logBeforehand("GetOutputStream.fromParentDocument") {
5455
DocumentsContract.createDocument(
5556
contentResolver,
5657
parentDocumentUri,
5758
MimeTypes.JPEG,
5859
fileName
5960
)!!.run {
60-
contentResolver.openOutputStream(this)!!
61+
contentResolver.openOutputStream(this)!! to this
6162
}
6263
}
6364

64-
fun untilQ(fileName: String): OutputStream = logBeforehand("GetOutputStream.untilQ") {
65+
fun untilQ(fileName: String): Pair<OutputStream, Uri> = logBeforehand("GetOutputStream.untilQ") {
6566
File(externalPicturesDir, fileName).run {
66-
FileOutputStream(this)
67+
FileOutputStream(this) to Uri.fromFile(this)
6768
}
6869
}
6970

7071
@RequiresApi(Build.VERSION_CODES.Q)
71-
fun postQ(fileName: String, contentResolver: ContentResolver): OutputStream = logBeforehand("GetOutputStream.postQ") {
72+
fun postQ(fileName: String, contentResolver: ContentResolver): Pair<OutputStream, Uri> = logBeforehand("GetOutputStream.postQ") {
7273
contentResolver.insert(
7374
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
7475
ContentValues().apply {
@@ -77,7 +78,7 @@ private object GetOutputStream{
7778
put(MediaStore.MediaColumns.MIME_TYPE, MimeTypes.JPEG)
7879
}
7980
)!!.let { newUri ->
80-
contentResolver.openOutputStream(newUri)!!
81+
contentResolver.openOutputStream(newUri)!! to newUri
8182
}
8283
}
8384
}

0 commit comments

Comments
 (0)