From bb5e0d435d8086e095bb456edc2f84beb9a321a5 Mon Sep 17 00:00:00 2001 From: pc112 Date: Wed, 28 Oct 2020 11:51:28 +0530 Subject: [PATCH] Implemented features #7 Supported to multiple items select. 1. Can be a button or a "Tick" Icon, when done. 2. Can be predefined & restrict "How many item can be chosen" 3. Chosen list should remain intact when Recyclerview Filter items --- .../sheetselection/demo/MainActivity.kt | 54 ++++++++--- .../sheetselection/SheetSelection.kt | 89 +++++++++++++++---- .../sheetselection/SheetSelectionAdapter.kt | 7 +- .../sheetselection/SheetSelectionItem.kt | 1 + .../res/layout/dialog_sheet_selection.xml | 13 +++ .../src/main/res/values/strings.xml | 4 + 6 files changed, 134 insertions(+), 34 deletions(-) create mode 100644 sheetselection/src/main/res/values/strings.xml diff --git a/app/src/main/java/com/minibugdev/sheetselection/demo/MainActivity.kt b/app/src/main/java/com/minibugdev/sheetselection/demo/MainActivity.kt index e0ac98a..55b3293 100644 --- a/app/src/main/java/com/minibugdev/sheetselection/demo/MainActivity.kt +++ b/app/src/main/java/com/minibugdev/sheetselection/demo/MainActivity.kt @@ -1,12 +1,17 @@ package com.minibugdev.sheetselection.demo import android.os.Bundle +import android.util.Log import androidx.appcompat.app.AppCompatActivity import com.minibugdev.sheetselection.SheetSelection import com.minibugdev.sheetselection.SheetSelectionItem import kotlinx.android.synthetic.main.activity_main.* +import java.util.* class MainActivity : AppCompatActivity() { + companion object { + private const val TAG = "MainActivity" + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -14,22 +19,35 @@ class MainActivity : AppCompatActivity() { buttonDefaultSheetSelection.setOnClickListener { val items = listOf( - SheetSelectionItem("1", "Item #1", R.drawable.ic_extension), - SheetSelectionItem("2", "Item #2", R.drawable.ic_nature), - SheetSelectionItem("3", "Item #3", R.drawable.ic_fingerprint), - SheetSelectionItem("4", "Item #4", R.drawable.ic_face), - SheetSelectionItem("5", "Item #5", R.drawable.ic_extension), - SheetSelectionItem("6", "Item #6", R.drawable.ic_fingerprint) + SheetSelectionItem("1", "Item #1", false, R.drawable.ic_extension), + SheetSelectionItem("2", "Item #2", false, R.drawable.ic_nature), + SheetSelectionItem("3", "Item #3", false, R.drawable.ic_fingerprint), + SheetSelectionItem("4", "Item #4", false, R.drawable.ic_face), + SheetSelectionItem("5", "Item #5", true, R.drawable.ic_extension), + SheetSelectionItem("6", "Item #6", false, R.drawable.ic_fingerprint) ) SheetSelection.Builder(this) .title("Sheet Selection") .items(items) - .selectedPosition(2) + //This will enable multiple Item choose feature + .forMultipleSelection(true) + //Maximum item choose limit + .maxItemChooseCount(2) + // Also you can use this + // .maxItemChooseCount(2, Max Item reached) .showDraggedIndicator(true) .searchEnabled(true) - .onItemClickListener { item, position -> - textview.text = "You selected `${item.value}`, At position [$position]." + .onCompleteListener { + if (it.isEmpty()) + return@onCompleteListener + + // Do what ever you want with these selected items. + Log.e(TAG, "OnCompleteSelection: $it") + for (sheetSelectionItem in it) { + Log.e(TAG, "OnCompleteSelection: ${sheetSelectionItem.value}") + } + textview.text = "You selected ${it[0].value}." } .show() } @@ -43,18 +61,30 @@ class MainActivity : AppCompatActivity() { SheetSelectionItem( key = "key_$it", value = "Custom $it", + isChecked = Random().nextBoolean(), icon = R.drawable.ic_motorcycle ) } ) - .selectedPosition(2) + //.selectedPosition(2) .showDraggedIndicator(true) .searchEnabled(true) + .forMultipleSelection(true) .searchNotFoundText("Nothing!!") .theme(R.style.Theme_Custom_SheetSelection) - .onItemClickListener { item, position -> - textview.text = "You selected `${item.value}`, At position [$position]." + .onCompleteListener { + if (it.isEmpty()) + return@onCompleteListener + + // Do what ever you want with these selected items. + for (sheetSelectionItem in it) { + Log.e(TAG, "OnCompleteSelection: $it") + } + textview.text = "You selected ${it[0].value}, At position" } +// .onItemClickListener { item, position -> +// textview.text = "You selected `${item.value}`, At position [$position]." +// } .show() } } diff --git a/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelection.kt b/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelection.kt index 3a87f83..c6612ff 100644 --- a/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelection.kt +++ b/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelection.kt @@ -2,9 +2,11 @@ package com.minibugdev.sheetselection import android.content.Context import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.Toast import androidx.annotation.StringRes import androidx.annotation.StyleRes import androidx.appcompat.widget.SearchView @@ -16,14 +18,28 @@ import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialogFragment import kotlinx.android.synthetic.main.dialog_sheet_selection.* +typealias OnCompleteListener = (ArrayList) -> Unit + class SheetSelection private constructor() : BottomSheetDialogFragment() { + private var onMultipleItemClickListener: OnCompleteListener? = null + private var previousList: List = emptyList() + private var selectedItemsList : ArrayList = ArrayList() + private val maxItemsChooseCount: Int by lazy { + arguments?.getInt(ARGS_MAX_ITEM_CHOOSE_COUNT) ?: Int.MAX_VALUE + } + private val maxItemsChooseCountMsg: String? by lazy { + arguments?.getString(ARGS_MAX_ITEM_CHOOSE_MESSAGE) + } - var onItemClickListener: OnItemSelectedListener? = null private val adapter by lazy { + previousList = arguments?.getParcelableArrayList(ARGS_ITEMS) ?: emptyList() + for (sheetSelectionItem in previousList) { + if(sheetSelectionItem.isChecked) + selectedItemsList.add(sheetSelectionItem) + } SheetSelectionAdapter( - source = arguments?.getParcelableArrayList(ARGS_ITEMS) ?: emptyList(), - selectedPosition = arguments?.getInt(ARGS_SELECTED_POSITION, NO_SELECT) ?: NO_SELECT, + source = previousList, searchNotFoundText = arguments?.getString(ARGS_SEARCH_NOT_FOUND_TEXT) ?: "Search not found.", onItemSelectedListener = onItemSelectedListener ) @@ -75,6 +91,11 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() { recyclerViewSelectionItems.setHasFixedSize(true) recyclerViewSelectionItems.adapter = adapter } + + doneButton.setOnClickListener{ + dismiss() + onMultipleItemClickListener?.invoke(selectedItemsList) + } } private fun updateSheetHeight(viewHeight: Int) { @@ -83,8 +104,33 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() { } private val onItemSelectedListener: OnItemSelectedListener = { item, position -> - dismiss() - onItemClickListener?.invoke(item, position) + if(arguments?.getBoolean(ARGS_FOR_MULTIPLE_SELECTION, false) == true){ + if(previousList.isNotEmpty()){ + val clickedItemInList = previousList.first { listItem -> listItem == item } + if(selectedItemsList.contains(clickedItemInList)){ + selectedItemsList.remove(clickedItemInList) + clickedItemInList.isChecked = false + adapter.notifyItemChanged(position) + } else { + if(selectedItemsList.size < maxItemsChooseCount){ + selectedItemsList.add(clickedItemInList) + clickedItemInList.isChecked = true + adapter.notifyItemChanged(position) + } else { + Toast.makeText( + requireContext(), + if(maxItemsChooseCountMsg.isNullOrEmpty()) "Cannot choose more than $maxItemsChooseCount items" else maxItemsChooseCountMsg, + Toast.LENGTH_SHORT + ).show() + } + } + } + } else { + dismiss() + selectedItemsList.clear() + selectedItemsList.add(item) + onMultipleItemClickListener?.invoke(selectedItemsList) + } } private val onSearchClickListener = View.OnClickListener { @@ -125,11 +171,13 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() { private var themeId: Int = R.style.Theme_SheetSelection private var title: String? = null private var items: List = emptyList() - private var selectedPosition: Int = NO_SELECT private var showDraggedIndicator: Boolean = false private var searchEnabled: Boolean = false + private var forMultipleSelection: Boolean = false + private var maxItemChooseCount: Int = 0 + private var maxItemChooseMessage: String? = null private var searchNotFoundText: String? = null - private var listener: OnItemSelectedListener? = null + private var listener: OnCompleteListener? = null fun theme(@StyleRes themeId: Int) = apply { this.themeId = themeId @@ -139,10 +187,6 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() { this.title = title } - fun selectedPosition(position: Int) = apply { - this.selectedPosition = position - } - fun items(items: List) = apply { this.items = items } @@ -164,11 +208,20 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() { this.searchNotFoundText = text } + fun forMultipleSelection(enabled: Boolean) = apply { + this.forMultipleSelection = enabled + } + + fun maxItemChooseCount(count: Int, message : String? = null) = apply { + this.maxItemChooseCount = count + this.maxItemChooseMessage = message + } + fun searchNotFoundText(@StringRes textResId: Int) = apply { this.searchNotFoundText = context.getString(textResId) } - fun onItemClickListener(listener: OnItemSelectedListener) = apply { + fun onCompleteListener(listener: OnCompleteListener) = apply { this.listener = listener } @@ -176,14 +229,16 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() { arguments = Bundle() .apply { putInt(ARGS_THEME, themeId) + putInt(ARGS_MAX_ITEM_CHOOSE_COUNT, maxItemChooseCount) + putString(ARGS_MAX_ITEM_CHOOSE_MESSAGE, maxItemChooseMessage) putString(ARGS_TITLE, title) putParcelableArrayList(ARGS_ITEMS, ArrayList(items)) - putInt(ARGS_SELECTED_POSITION, selectedPosition) putBoolean(ARGS_SHOW_DRAGGED_INDICATOR, showDraggedIndicator) putBoolean(ARGS_SEARCH_ENABLED, searchEnabled) + putBoolean(ARGS_FOR_MULTIPLE_SELECTION, forMultipleSelection) putString(ARGS_SEARCH_NOT_FOUND_TEXT, searchNotFoundText) } - onItemClickListener = listener + onMultipleItemClickListener = listener } fun show() { @@ -194,14 +249,16 @@ class SheetSelection private constructor() : BottomSheetDialogFragment() { } companion object { + private const val TAG = "SheetSelection" const val NO_SELECT = -1 - private const val ARGS_THEME = "SheetSelection:ARGS_THEME" private const val ARGS_TITLE = "SheetSelection:ARGS_TITLE" private const val ARGS_ITEMS = "SheetSelection:ARGS_ITEMS" private const val ARGS_SEARCH_NOT_FOUND_TEXT = "SheetSelection:ARGS_SEARCH_NOT_FOUND_TEXT" - private const val ARGS_SELECTED_POSITION = "SheetSelection:ARGS_SELECTED_POSITION" private const val ARGS_SHOW_DRAGGED_INDICATOR = "SheetSelection:ARGS_SHOW_DRAGGED_INDICATOR" private const val ARGS_SEARCH_ENABLED = "SheetSelection:ARGS_SEARCH_ENABLED" + private const val ARGS_FOR_MULTIPLE_SELECTION = "SheetSelection:ARGS_FOR_MULTIPLE_SELECTION" + private const val ARGS_MAX_ITEM_CHOOSE_COUNT = "SheetSelection:ARGS_MAX_ITEM_CHOOSE_COUNT" + private const val ARGS_MAX_ITEM_CHOOSE_MESSAGE = "SheetSelection:ARGS_MAX_ITEM_CHOOSE_MESSAGE" } } \ No newline at end of file diff --git a/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelectionAdapter.kt b/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelectionAdapter.kt index a9d2cd0..cc9f689 100644 --- a/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelectionAdapter.kt +++ b/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelectionAdapter.kt @@ -11,7 +11,6 @@ typealias OnItemSelectedListener = (item: SheetSelectionItem, position: Int) -> class SheetSelectionAdapter( private val source: List, - private val selectedPosition: Int, private val searchNotFoundText: String, private val onItemSelectedListener: OnItemSelectedListener? ) : RecyclerView.Adapter() { @@ -40,7 +39,6 @@ class SheetSelectionAdapter( holder.onBindView( item = items[position], position = position, - selected = position == selectedPosition, onItemSelectedListener = onItemSelectedListener ) } @@ -73,13 +71,10 @@ class SheetSelectionAdapter( fun onBindView( item: SheetSelectionItem, position: Int, - selected: Boolean, onItemSelectedListener: OnItemSelectedListener? ) { - val selectedIcon = if (selected) R.drawable.ic_check else 0 - textViewItem.setCompoundDrawablesWithIntrinsicBounds(item.icon ?: 0, 0, selectedIcon, 0) + textViewItem.setCompoundDrawablesWithIntrinsicBounds(item.icon ?: 0, 0, if(item.isChecked) R.drawable.ic_check else 0 , 0) textViewItem.text = item.value - textViewItem.setOnClickListener { onItemSelectedListener?.invoke(item, position) } diff --git a/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelectionItem.kt b/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelectionItem.kt index f295b91..e8f8626 100644 --- a/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelectionItem.kt +++ b/sheetselection/src/main/java/com/minibugdev/sheetselection/SheetSelectionItem.kt @@ -8,5 +8,6 @@ import kotlinx.android.parcel.Parcelize data class SheetSelectionItem( val key: String, val value: String, + var isChecked: Boolean = false, @DrawableRes val icon: Int? = null ) : Parcelable \ No newline at end of file diff --git a/sheetselection/src/main/res/layout/dialog_sheet_selection.xml b/sheetselection/src/main/res/layout/dialog_sheet_selection.xml index a0f7829..8c7b41f 100644 --- a/sheetselection/src/main/res/layout/dialog_sheet_selection.xml +++ b/sheetselection/src/main/res/layout/dialog_sheet_selection.xml @@ -63,4 +63,17 @@ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" tools:itemCount="10" tools:listitem="@layout/row_selection_item" /> + + diff --git a/sheetselection/src/main/res/values/strings.xml b/sheetselection/src/main/res/values/strings.xml new file mode 100644 index 0000000..e7587c2 --- /dev/null +++ b/sheetselection/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Done + \ No newline at end of file