Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Search, sorting #439

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
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