Skip to content

Commit 946a6b1

Browse files
authored
Merge pull request #11 from vedraj360/master
Extension-Based Filtering
2 parents d5bc4ed + 8e48ec2 commit 946a6b1

File tree

14 files changed

+613
-436
lines changed

14 files changed

+613
-436
lines changed

app/src/main/java/com/crazylegend/mediapicker/FragmentResult.kt

Lines changed: 159 additions & 142 deletions
Large diffs are not rendered by default.

app/src/main/java/com/crazylegend/mediapicker/MainActivity.kt

Lines changed: 145 additions & 159 deletions
Large diffs are not rendered by default.

imagepicker/README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ dependencies {
2727

2828

2929
//customized
30-
SingleImagePicker.showPicker(this, {
30+
SingleImagePicker.showPicker(this, extensions = arrayOf(),{
3131
loadingIndicatorTint = ContextCompat.getColor(this@MainActivity, R.color.colorPrimaryDark)
3232
titleTextModifier.apply {
3333
textAlignment = TextView.TEXT_ALIGNMENT_VIEW_START
@@ -50,6 +50,7 @@ dependencies {
5050
resID = R.drawable.ic_image
5151
}
5252
}, ::loadImage)
53+
// You can filter files by passing extensions like extensions = arrayOf("png","jpeg")
5354
```
5455

5556
4. How to use multi picker and check out [how to customize multi image picker](https://github.com/FunkyMuse/MediaPicker/wiki/Multi-image-video-picker-customization)
@@ -58,7 +59,7 @@ dependencies {
5859
MultiImagePicker.showPicker(this){ doSomethingWithImageList(it) }
5960

6061
//customized
61-
MultiImagePicker.showPicker(this, {
62+
MultiImagePicker.showPicker(this, extensions = arrayOf(), {
6263
setupBaseMultiPicker(
6364
tintForLoadingProgressBar = ContextCompat.getColor(this@MainActivity, R.color.colorPrimaryDark),
6465
gravityForSelectAndUnSelectIndicators = BaseMultiPickerModifier.Gravity.TOP_LEFT,

imagepicker/src/main/java/com/crazylegend/imagepicker/dialogs/multi/MultiImagePickerBottomSheetDialog.kt

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ import com.google.android.material.button.MaterialButton
3030
* Created by crazy on 5/8/20 to long live and prosper !
3131
*/
3232
internal class MultiImagePickerBottomSheetDialog : AbstractBottomSheetDialogFragment(),
33-
MultiPickerContracts {
33+
MultiPickerContracts {
3434

35+
var extensions: Array<String>? = arrayOf()
3536

3637
override val layout: Int
3738
get() = super.layout
@@ -45,38 +46,54 @@ internal class MultiImagePickerBottomSheetDialog : AbstractBottomSheetDialogFrag
4546
MultiSelectAdapter(modifier)
4647
}
4748
override val askForStoragePermission =
48-
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
49-
if (it) {
50-
imagesVM.loadImages()
51-
} else {
52-
Log.e(errorTag, "PERMISSION DENIED")
53-
dismissAllowingStateLoss()
54-
}
49+
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
50+
if (it) {
51+
imagesVM.loadImages(extensions = extensions)
52+
} else {
53+
Log.e(errorTag, "PERMISSION DENIED")
54+
dismissAllowingStateLoss()
5555
}
56+
}
5657

5758
@Suppress("UNCHECKED_CAST")
5859
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
5960
super.onViewCreated(view, savedInstanceState)
60-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU){
61+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
6162
askForStoragePermission.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
6263
} else {
6364
askForStoragePermission.launch(Manifest.permission.READ_MEDIA_IMAGES)
6465
}
6566

6667
setupUIForMultiPicker(
67-
binding.gallery, multiSelectAdapter, binding.doneButton, binding.title, binding.loadingIndicator, modifier?.loadingIndicatorTint,
68-
::applyDoneButtonModifications, ::applyTitleModifications)
68+
binding.gallery,
69+
multiSelectAdapter,
70+
binding.doneButton,
71+
binding.title,
72+
binding.loadingIndicator,
73+
modifier?.loadingIndicatorTint,
74+
::applyDoneButtonModifications,
75+
::applyTitleModifications
76+
)
6977

7078
imagesVM.images.observe(viewLifecycleOwner) {
71-
setupList(multiSelectAdapter, it, binding.noContentText, modifier?.noContentTextModifier)
79+
setupList(
80+
multiSelectAdapter,
81+
it,
82+
binding.noContentText,
83+
modifier?.noContentTextModifier
84+
)
7285
}
7386
handleUIIndicator(imagesVM.loadingIndicator, binding.loadingIndicator)
7487

7588

7689
binding.doneButton.setOnClickListener {
77-
val imagesList = multiSelectAdapter.currentList.filter { it.isSelected } as? List<ImageModel>
90+
val imagesList =
91+
multiSelectAdapter.currentList.filter { it.isSelected } as? List<ImageModel>
7892
?: emptyList()
79-
setFragmentResult(MultiImagePicker.MULTI_IMAGE_REQUEST_KEY, bundleOf(MultiImagePicker.ON_MULTI_IMAGE_PICK_KEY to imagesList))
93+
setFragmentResult(
94+
MultiImagePicker.MULTI_IMAGE_REQUEST_KEY,
95+
bundleOf(MultiImagePicker.ON_MULTI_IMAGE_PICK_KEY to imagesList)
96+
)
8097
onImagesPicked?.onImagesPicked(imagesList)
8198
dismissAllowingStateLoss()
8299
}

imagepicker/src/main/java/com/crazylegend/imagepicker/dialogs/single/SingleImagePickerBottomSheetDialog.kt

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ import com.crazylegend.imagepicker.pickers.SingleImagePicker
2727
/**
2828
* Created by crazy on 5/8/20 to long live and prosper !
2929
*/
30-
internal class SingleImagePickerBottomSheetDialog : AbstractBottomSheetDialogFragment(), SinglePickerContracts {
30+
internal class SingleImagePickerBottomSheetDialog : AbstractBottomSheetDialogFragment(),
31+
SinglePickerContracts {
3132

3233
override val layout: Int
3334
get() = super.layout
@@ -36,34 +37,46 @@ internal class SingleImagePickerBottomSheetDialog : AbstractBottomSheetDialogFra
3637
override val imagesVM by viewModels<ImagesVM>()
3738
override val modifier: BaseSinglePickerModifier?
3839
get() = arguments?.getParcelable(modifierTag)
40+
var extensions: Array<String>? = arrayOf()
3941

4042
override val singleAdapter by lazy {
4143
SingleAdapter(modifier?.viewHolderPlaceholderModifier) {
4244
val image = it as ImageModel
43-
setFragmentResult(SingleImagePicker.SINGLE_IMAGE_REQUEST_KEY, bundleOf(SingleImagePicker.ON_SINGLE_IMAGE_PICK_KEY to image))
45+
setFragmentResult(
46+
SingleImagePicker.SINGLE_IMAGE_REQUEST_KEY,
47+
bundleOf(SingleImagePicker.ON_SINGLE_IMAGE_PICK_KEY to image)
48+
)
4449
onImagePicked?.forImage(image)
4550
dismissAllowingStateLoss()
4651
}
4752
}
4853

49-
override val askForStoragePermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) {
50-
if (it) {
51-
imagesVM.loadImages()
52-
} else {
53-
Log.e(errorTag, "PERMISSION DENIED")
54-
dismissAllowingStateLoss()
54+
override val askForStoragePermission =
55+
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
56+
if (it) {
57+
imagesVM.loadImages(extensions = extensions)
58+
} else {
59+
Log.e(errorTag, "PERMISSION DENIED")
60+
dismissAllowingStateLoss()
61+
}
5562
}
56-
}
5763

5864

5965
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
6066
super.onViewCreated(view, savedInstanceState)
61-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU){
67+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
6268
askForStoragePermission.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
6369
} else {
6470
askForStoragePermission.launch(Manifest.permission.READ_MEDIA_IMAGES)
6571
}
66-
setupUIForSinglePicker(binding.gallery, singleAdapter, binding.title, binding.loadingIndicator, modifier?.loadingIndicatorTint, ::applyTitleModifications)
72+
setupUIForSinglePicker(
73+
binding.gallery,
74+
singleAdapter,
75+
binding.title,
76+
binding.loadingIndicator,
77+
modifier?.loadingIndicatorTint,
78+
::applyTitleModifications
79+
)
6780
imagesVM.images.observe(viewLifecycleOwner) {
6881
setupList(singleAdapter, it, binding.noContentText, modifier?.noContentTextModifier)
6982
}

imagepicker/src/main/java/com/crazylegend/imagepicker/images/ImagesVM.kt

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.crazylegend.imagepicker.images
33
import android.app.Application
44
import android.content.ContentUris
55
import android.provider.MediaStore
6+
import android.util.Log
67
import androidx.core.database.getIntOrNull
78
import androidx.core.database.getLongOrNull
89
import androidx.core.database.getStringOrNull
@@ -22,31 +23,36 @@ import kotlinx.coroutines.withContext
2223
/**
2324
* Created by crazy on 5/8/20 to long live and prosper !
2425
*/
25-
internal class ImagesVM(application: Application, stateHandle: SavedStateHandle) : AbstractAVM(application, stateHandle) {
26+
internal class ImagesVM(application: Application, stateHandle: SavedStateHandle) :
27+
AbstractAVM(application, stateHandle) {
2628

2729
private val imagesData = MutableLiveData<List<ImageModel>>()
2830
val images: LiveData<List<ImageModel>> = imagesData
2931

3032

31-
fun loadImages(sortOrder: SortOrder = SortOrder.DATE_ADDED_DESC) {
33+
fun loadImages(sortOrder: SortOrder = SortOrder.DATE_ADDED_DESC, extensions: Array<String>?) {
3234
if (canLoad) {
3335
viewModelScope.launch {
34-
imagesData.postValue(queryImages(sortOrder))
35-
initializeContentObserver(sortOrder)
36+
imagesData.postValue(queryImages(sortOrder, extensions))
37+
initializeContentObserver(sortOrder, extensions)
3638
}
3739
}
3840
}
3941

40-
private fun initializeContentObserver(sortOrder: SortOrder) {
42+
private fun initializeContentObserver(sortOrder: SortOrder, extensions: Array<String>?) {
4143
if (contentObserver == null) {
42-
contentObserver = contentResolver.registerObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI) {
43-
setCanLoad()
44-
loadImages(sortOrder)
45-
}
44+
contentObserver =
45+
contentResolver.registerObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI) {
46+
setCanLoad()
47+
loadImages(sortOrder, extensions)
48+
}
4649
}
4750
}
4851

49-
private suspend fun queryImages(order: SortOrder): List<ImageModel> {
52+
private suspend fun queryImages(
53+
order: SortOrder,
54+
extensions: Array<String>?
55+
): List<ImageModel> {
5056
loadingIndicatorData.value = true
5157

5258
val images = mutableListOf<ImageModel>()
@@ -66,23 +72,41 @@ internal class ImagesVM(application: Application, stateHandle: SavedStateHandle)
6672
}
6773
withContext(Dispatchers.IO) {
6874
val projection =
69-
arrayOf(
70-
MediaStore.Images.Media._ID,
71-
MediaStore.Images.Media.DISPLAY_NAME,
72-
MediaStore.Images.Media.DATE_ADDED,
73-
MediaStore.Images.Media.DATE_MODIFIED,
74-
MediaStore.Images.Media.DESCRIPTION,
75-
MediaStore.Images.Media.SIZE,
76-
MediaStore.Images.Media.WIDTH,
77-
MediaStore.Images.Media.HEIGHT
78-
)
75+
arrayOf(
76+
MediaStore.Images.Media._ID,
77+
MediaStore.Images.Media.DISPLAY_NAME,
78+
MediaStore.Images.Media.DATE_ADDED,
79+
MediaStore.Images.Media.DATE_MODIFIED,
80+
MediaStore.Images.Media.DESCRIPTION,
81+
MediaStore.Images.Media.SIZE,
82+
MediaStore.Images.Media.WIDTH,
83+
MediaStore.Images.Media.HEIGHT
84+
)
85+
86+
val selection = if (!extensions.isNullOrEmpty()) {
87+
val extensionSelection = extensions.joinToString(separator = " OR ") {
88+
"${MediaStore.Video.Media.DATA} LIKE ?"
89+
}
90+
"($extensionSelection)"
91+
} else {
92+
null
93+
}
7994

95+
Log.e("TAG", "queryImages: selection $selection" )
8096

97+
val selectionArgs = extensions?.map { "%.$it" }?.toTypedArray()
8198

82-
contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, sortOrder)?.use { cursor ->
99+
contentResolver.query(
100+
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
101+
projection,
102+
selection,
103+
selectionArgs,
104+
sortOrder
105+
)?.use { cursor ->
83106

84107
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
85-
val displayNameColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
108+
val displayNameColumn =
109+
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
86110
val dateAddedColumn = cursor.getSafeColumn(MediaStore.Images.Media.DATE_ADDED)
87111
val dateModifiedColumn = cursor.getSafeColumn(MediaStore.Images.Media.DATE_MODIFIED)
88112
val descriptionColumn = cursor.getSafeColumn(MediaStore.Images.Media.DESCRIPTION)
@@ -101,10 +125,21 @@ internal class ImagesVM(application: Application, stateHandle: SavedStateHandle)
101125
val width = widthColumn?.let { cursor.getIntOrNull(it) }
102126
val height = heightColumn?.let { cursor.getIntOrNull(it) }
103127

104-
val contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
105-
val image = ImageModel(id, displayName, dateAdded, contentUri, dateModified, description, size, width, height)
128+
val contentUri =
129+
ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
130+
val image = ImageModel(
131+
id,
132+
displayName,
133+
dateAdded,
134+
contentUri,
135+
dateModified,
136+
description,
137+
size,
138+
width,
139+
height
140+
)
106141
image.isSelected = imagesData.value?.find { it.id == image.id }?.isSelected
107-
?: false
142+
?: false
108143
images += image
109144
}
110145
}

imagepicker/src/main/java/com/crazylegend/imagepicker/pickers/MultiImagePicker.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package com.crazylegend.imagepicker.pickers
22

3-
import android.Manifest.permission.READ_EXTERNAL_STORAGE
43
import android.content.Context
54
import android.util.Log
6-
import androidx.annotation.RequiresPermission
75
import androidx.fragment.app.FragmentManager
86
import com.crazylegend.core.modifiers.base.BaseMultiPickerModifier
97
import com.crazylegend.core.setupModifier
@@ -27,10 +25,11 @@ object MultiImagePicker {
2725
fun restoreListener(context: Context, imagesList: (list: List<ImageModel>) -> Unit = {}) {
2826
val manager = context.setupManager()
2927
when (val fragment = manager.findFragmentByTag(MULTI_PICKER_BOTTOM_SHEET)
30-
?: manager.findFragmentByTag(MULTI_PICKER_DIALOG)) {
28+
?: manager.findFragmentByTag(MULTI_PICKER_DIALOG)) {
3129
is MultiImagePickerBottomSheetDialog -> {
3230
fragment.onImagesPicked = onImagesDSL(imagesList)
3331
}
32+
3433
null -> {
3534
Log.e(MultiImagePicker::class.java.name, "FRAGMENT NOT FOUND")
3635
}
@@ -39,24 +38,29 @@ object MultiImagePicker {
3938

4039

4140
fun showPicker(
42-
context: Context, multiImagePickerModifier: BaseMultiPickerModifier.() -> Unit = {},
43-
imagesList: (list: List<ImageModel>) -> Unit = {}
41+
context: Context, extensions: Array<String>? = arrayOf(),
42+
multiImagePickerModifier: BaseMultiPickerModifier.() -> Unit = {},
43+
imagesList: (list: List<ImageModel>) -> Unit = {}
4444
) {
4545
val manager = context.setupManager()
4646
val modifier = setupModifier(multiImagePickerModifier)
4747
with(MultiImagePickerBottomSheetDialog()) {
48+
this.extensions = extensions
4849
addModifier(modifier)
4950
onImagesPicked = onImagesDSL(imagesList)
5051
show(manager, MULTI_PICKER_BOTTOM_SHEET)
5152
}
5253
}
5354

5455
fun showPicker(
55-
fragmentManager: FragmentManager, multiImagePickerModifier: BaseMultiPickerModifier.() -> Unit = {},
56-
imagesList: (list: List<ImageModel>) -> Unit = {}
56+
fragmentManager: FragmentManager,
57+
extensions: Array<String>? = arrayOf(),
58+
multiImagePickerModifier: BaseMultiPickerModifier.() -> Unit = {},
59+
imagesList: (list: List<ImageModel>) -> Unit = {}
5760
) {
5861
val modifier = setupModifier(multiImagePickerModifier)
5962
with(MultiImagePickerBottomSheetDialog()) {
63+
this.extensions = extensions
6064
addModifier(modifier)
6165
onImagesPicked = onImagesDSL(imagesList)
6266
show(fragmentManager, MULTI_PICKER_BOTTOM_SHEET)

0 commit comments

Comments
 (0)