Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.
3 changes: 2 additions & 1 deletion imagepicker/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,9 @@ artifacts {
dependencies {
implementation "com.github.bumptech.glide:glide:4.14.2"
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.appcompat:appcompat:1.6.1'

implementation "androidx.core:core-ktx:$core_ktx_version"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class FolderPickerAdapter(
override fun getItemCount() = folders.size

class FolderViewHolder(binding: EfImagepickerItemFolderBinding) : ViewHolder(binding.root) {
val image = binding.image
val image = binding.imageView
val name = binding.tvName
val number = binding.tvNumber
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import android.provider.MediaStore
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.esafirm.imagepicker.R
Expand All @@ -25,6 +23,7 @@ class ImagePickerAdapter(
context: Context,
imageLoader: ImageLoader,
selectedImages: List<Image>,
private val isShowImageNames: Boolean,
private val itemClickListener: OnImageClickListener
) : BaseListAdapter<ImageViewHolder>(context, imageLoader) {

Expand Down Expand Up @@ -68,10 +67,9 @@ class ImagePickerAdapter(

if (ImagePickerUtils.isVideoFormat(image)) {
if (!videoDurationHolder.containsKey(image.id)) {
val uri =
Uri.withAppendedPath(MediaStore.Files.getContentUri("external"), "" + image.id)
videoDurationHolder[image.id] = ImagePickerUtils.getVideoDurationLabel(
context, uri
context = context,
uri = Uri.withAppendedPath(MediaStore.Files.getContentUri("external"), "" + image.id)
)
}

Expand All @@ -80,9 +78,15 @@ class ImagePickerAdapter(
}

viewHolder.apply {
if (isShowImageNames) {
nameView.text = image.name
bottomView.visibility = View.VISIBLE
} else {
bottomView.visibility = View.GONE
}
fileTypeIndicator.text = fileTypeLabel
fileTypeIndicator.visibility = if (showFileTypeIndicator) View.VISIBLE else View.GONE
alphaView.alpha = if (isSelected) 0.5f else 0f
selectedView.visibility = if (isSelected) View.VISIBLE else View.GONE
itemView.setOnClickListener {
val shouldSelect = itemClickListener(isSelected)

Expand All @@ -92,21 +96,27 @@ class ImagePickerAdapter(
addSelected(image, position)
}
}
container.foreground = if (isSelected) ContextCompat.getDrawable(
context,
R.drawable.ef_ic_done_white
) else null
}
}

private fun isSelected(image: Image): Boolean {
return selectedImages.any { it.path == image.path }
override fun getItemCount() = listDiffer.currentList.size

override fun getItemViewType(position: Int): Int {
return position
}

override fun getItemCount() = listDiffer.currentList.size
override fun getItemId(position: Int): Long {
return position.toLong()
}

fun setData(images: List<Image>, commitCallback: (() -> Unit)? = null) {
listDiffer.submitList(images) {
commitCallback?.invoke()
}
}

fun setData(images: List<Image>) {
listDiffer.submitList(images)
private fun isSelected(image: Image): Boolean {
return selectedImages.any { it.path == image.path }
}

private fun addSelected(image: Image, position: Int) {
Expand Down Expand Up @@ -143,8 +153,9 @@ class ImagePickerAdapter(

class ImageViewHolder(binding: EfImagepickerItemImageBinding) : ViewHolder(binding.root) {
val imageView = binding.imageView
val alphaView = binding.viewAlpha
val nameView = binding.tvImageName
val fileTypeIndicator = binding.efItemFileTypeIndicator
val container = binding.root as FrameLayout
val bottomView = binding.efBottomView
val selectedView = binding.viewSelected
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ package com.esafirm.imagepicker.features

import com.esafirm.imagepicker.helper.state.ObservableState
import com.esafirm.imagepicker.helper.state.SingleEvent
import com.esafirm.imagepicker.helper.state.asSingleEvent
import com.esafirm.imagepicker.model.Folder
import com.esafirm.imagepicker.model.Image

data class ImagePickerState(
val images: List<Image> = emptyList(),
val folders: List<Folder> = emptyList(),
// TODO: handle the transitions between folder and images in the view state as well
val isFolder: SingleEvent<Boolean>? = null,
val isFoldersMode: SingleEvent<Boolean>? = null,
val currentFolder: Folder? = null,
val isLoading: Boolean = false,
val error: SingleEvent<Throwable>? = null,
val finishPickImage: SingleEvent<List<Image>>? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import android.view.Menu
import android.view.MenuItem
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import android.view.View
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import com.esafirm.imagepicker.R
import com.esafirm.imagepicker.features.cameraonly.CameraOnlyConfig
Expand All @@ -26,6 +28,9 @@ class ImagePickerActivity : AppCompatActivity(), ImagePickerInteractionListener
private val cameraModule = ImagePickerComponentsHolder.cameraModule

private var actionBar: ActionBar? = null
private var optionsMenu: Menu? = null
private var searchView: SearchView? = null
private var isNeedSearch = true
private lateinit var imagePickerFragment: ImagePickerFragment

private val config: ImagePickerConfig? by lazy {
Expand Down Expand Up @@ -98,6 +103,8 @@ class ImagePickerActivity : AppCompatActivity(), ImagePickerInteractionListener
*/
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.ef_image_picker_menu_main, menu)
this.optionsMenu = menu
initSearchView(menu)
return true
}

Expand Down Expand Up @@ -129,6 +136,10 @@ class ImagePickerActivity : AppCompatActivity(), ImagePickerInteractionListener
imagePickerFragment.captureImage()
return true
}
if (id == R.id.menu_sort) {
imagePickerFragment.showSortPopupMenu(item)
return true
}
return super.onOptionsItemSelected(item)
}

Expand Down Expand Up @@ -158,13 +169,57 @@ class ImagePickerActivity : AppCompatActivity(), ImagePickerInteractionListener
}
}

//region Search

private fun initSearchView(menu: Menu) {
searchView = menu.findItem(R.id.menu_search).actionView as? SearchView
if (config?.isShowSearch == true) {
searchView?.setIconifiedByDefault(true)
searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
search(query)
return true
}

override fun onQueryTextChange(newText: String): Boolean {
search(newText)
return true
}
})
searchView?.setOnCloseListener {
search(null)
false
}
} else {
searchView?.visibility = View.GONE
}
}

private fun search(query: String?) {
if (isNeedSearch) {
imagePickerFragment.search(query)
}
}

private fun closeSearchView() {
// at the same time the onClose event is triggered, so isNeedSearch must be avoided reloading
isNeedSearch = false
searchView?.setQuery(null, false)
searchView?.isIconified = true
isNeedSearch = true
}

//endregion Search

/* --------------------------------------------------- */
/* > ImagePickerInteractionListener Methods */
/* --------------------------------------------------- */

override fun setTitle(title: String?) {
actionBar?.title = title
invalidateOptionsMenu()
if (optionsMenu != null) {
onPrepareOptionsMenu(optionsMenu!!)
}
}

override fun cancel() {
Expand All @@ -179,4 +234,8 @@ class ImagePickerActivity : AppCompatActivity(), ImagePickerInteractionListener
setResult(RESULT_OK, result)
finish()
}
}

override fun isFolderModeChanged() {
closeSearchView()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ class ImagePickerConfig(
override var savePath: ImagePickerSavePath = ImagePickerSavePath.DEFAULT,
override var returnMode: ReturnMode = ReturnMode.NONE,
override var isSaveImage: Boolean = true,
var showDoneButtonAlways: Boolean = false
var showDoneButtonAlways: Boolean = false,
var isShowSearch: Boolean = false,
var searchQuery: String? = null,
var isShowImageNames: Boolean = false,
var foldersSortMode: FolderSortMode = FolderSortMode.NONE,
var imagesSortMode: ImageSortMode = ImageSortMode.NONE
) : BaseConfig(), Parcelable {

@IgnoredOnParcel
Expand Down
Loading