Merge branch 'tag_filters' into range_filter
# Conflicts: # base-filters/README.md
This commit is contained in:
commit
853d32236a
|
|
@ -13,16 +13,18 @@
|
||||||
### Как использовать
|
### Как использовать
|
||||||
``` kotlin
|
``` kotlin
|
||||||
val selectorView = ListSelectionView<DefaultSelectionItem, SelectionItemViewHolder<DefaultSelectionItem>>(context)
|
val selectorView = ListSelectionView<DefaultSelectionItem, SelectionItemViewHolder<DefaultSelectionItem>>(context)
|
||||||
.setItems(navArgs.items)
|
.Builder()
|
||||||
.addItemDecoration((TopDividerItemDecoration(
|
.setItems(navArgs.items)
|
||||||
context = requireContext(),
|
.addItemDecoration((TopDividerItemDecoration(
|
||||||
drawableId = R.drawable.list_divider_1dp,
|
context = requireContext(),
|
||||||
startMargin = START_MARGIN_DIVIDER_DP.px
|
drawableId = R.drawable.list_divider_1dp,
|
||||||
)))
|
startMargin = START_MARGIN_DIVIDER_DP.px
|
||||||
.withSelectionType(ListSelectionView.SelectionType.SINGLE_SELECT)
|
)))
|
||||||
.onResultListener { items ->
|
.withSelectionType(ListSelectionView.SelectionType.SINGLE_SELECT)
|
||||||
viewModel.dispatchAction(SelectItemAction.SelectItem(items)) }
|
.onResultListener { items ->
|
||||||
.build()
|
viewModel.dispatchAction(SelectItemAction.SelectItem(items))
|
||||||
|
}
|
||||||
|
.build()
|
||||||
```
|
```
|
||||||
### Конфигурации
|
### Конфигурации
|
||||||
* при создании `ListSelectionView<ItemType, HolderType>` необходимо передлать `ItemType` - класс модели данных в списке, `HolderType` - класс viewHolder-а в recyclerView.
|
* при создании `ListSelectionView<ItemType, HolderType>` необходимо передлать `ItemType` - класс модели данных в списке, `HolderType` - класс viewHolder-а в recyclerView.
|
||||||
|
|
@ -35,15 +37,16 @@ val selectorView = ListSelectionView<DefaultSelectionItem, SelectionItemViewHold
|
||||||
* метод `showInHolder(HolderFactoryType<ItemType>)` используется для определения кастомного viewHolder для списка с недефолтной разметкой.
|
* метод `showInHolder(HolderFactoryType<ItemType>)` используется для определения кастомного viewHolder для списка с недефолтной разметкой.
|
||||||
``` kotlin
|
``` kotlin
|
||||||
val selectorView = ListSelectionView<TestSelectionItem, TestItemViewHolder>(context)
|
val selectorView = ListSelectionView<TestSelectionItem, TestItemViewHolder>(context)
|
||||||
.showInHolder { parent, clickListener, selectionType ->
|
.Builder()
|
||||||
TestItemViewHolder(
|
.showInHolder { parent, clickListener, selectionType ->
|
||||||
binding = TestSelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
TestItemViewHolder(
|
||||||
onItemSelectAction = clickListener,
|
binding = TestSelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||||
selectionType = selectionType
|
onItemSelectAction = clickListener,
|
||||||
)
|
selectionType = selectionType
|
||||||
}
|
)
|
||||||
...
|
}
|
||||||
.build()
|
...
|
||||||
|
.build()
|
||||||
```
|
```
|
||||||
* колбэк `onSelectedItemsListener(listener: OnSelectedItemsListener<ItemType>)` можно использовать для получения списка всех элементов `ItemType` после каждого выбора
|
* колбэк `onSelectedItemsListener(listener: OnSelectedItemsListener<ItemType>)` можно использовать для получения списка всех элементов `ItemType` после каждого выбора
|
||||||
* колбэк `onSelectedItemListener(listener: OnSelectedItemListener<ItemType>)` можно использовать для получения элемента списка `ItemType`, по которому произошел клик
|
* колбэк `onSelectedItemListener(listener: OnSelectedItemListener<ItemType>)` можно использовать для получения элемента списка `ItemType`, по которому произошел клик
|
||||||
|
|
@ -80,8 +83,9 @@ val selectorView = ListSelectionView<TestSelectionItem, TestItemViewHolder>(cont
|
||||||
``` kotlin
|
``` kotlin
|
||||||
val newContext = ContextThemeWrapper(requireContext(), R.style.Theme_Custom_FilterSelection)
|
val newContext = ContextThemeWrapper(requireContext(), R.style.Theme_Custom_FilterSelection)
|
||||||
val selectorView = ListSelectionView(newContext)
|
val selectorView = ListSelectionView(newContext)
|
||||||
...
|
.Builder()
|
||||||
.build()
|
...
|
||||||
|
.build()
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2. Выбор одного/нескольких значений из перечня тегов
|
## 2. Выбор одного/нескольких значений из перечня тегов
|
||||||
|
|
@ -92,14 +96,14 @@ val selectorView = ListSelectionView(newContext)
|
||||||
### Как использовать
|
### Как использовать
|
||||||
``` kotlin
|
``` kotlin
|
||||||
binding.tagItemLayout
|
binding.tagItemLayout
|
||||||
.setSpacing(16)
|
.Builder(getFilterItem())
|
||||||
.setSelectionType(SelectionType.MULTI_SELECT) // по умолчанию
|
.setSpacing(16)
|
||||||
.isSingleLine(false) // по умолчанию
|
.setSelectionType(SelectionType.MULTI_SELECT) // по умолчанию
|
||||||
.onPropertySelectedAction { filterProperty: FilterProperty ->
|
.isSingleLine(false) // по умолчанию
|
||||||
//Do something
|
.onPropertySelectedAction { filterProperty: FilterProperty ->
|
||||||
}
|
//Do something
|
||||||
.build(getFilterItem())
|
|
||||||
}
|
}
|
||||||
|
.build()
|
||||||
```
|
```
|
||||||
### Конфигурации
|
### Конфигурации
|
||||||
* метод `setSelectionType(SelectionType)` конфигурирует тип выбора:
|
* метод `setSelectionType(SelectionType)` конфигурирует тип выбора:
|
||||||
|
|
@ -109,9 +113,10 @@ binding.tagItemLayout
|
||||||
* `setTagLayout(Int)` устанавливает разметку для тега. Если не задано - то используется дефолтная разметка `layout_default_tag.xml`
|
* `setTagLayout(Int)` устанавливает разметку для тега. Если не задано - то используется дефолтная разметка `layout_default_tag.xml`
|
||||||
* `setMaxTagCount(Int)` позволяет ограничить количество отображаемых тегов. По умолчанию ограничения нет.
|
* `setMaxTagCount(Int)` позволяет ограничить количество отображаемых тегов. По умолчанию ограничения нет.
|
||||||
* `setMoreTagLayout(Int, String)` устанавливает разметку для тега, который отображается для дополнительного тега. Если не указана - то тег не будет создан
|
* `setMoreTagLayout(Int, String)` устанавливает разметку для тега, который отображается для дополнительного тега. Если не указана - то тег не будет создан
|
||||||
* `setSpacing(Int)`, `setSpacingHorizontal(Int`) и мsetSpacingVertical(Int)` можно использовать для настройки расстояния между тегами. По умолчанию - 0
|
* `setSpacing(Int)`, `setSpacingHorizontal(Int)` и `setSpacingVertical(Int)` можно использовать для настройки расстояния между тегами. По умолчанию - 0
|
||||||
* `onMoreValuesAction(FilterMoreAction)` и `onPropertySelectedAction(PropertySelectedAction)` используются для передачи колбэков на клик по тегу типа "Еще" и обычного тега соответственно
|
* `onMoreValuesAction(FilterMoreAction)` и `onPropertySelectedAction(PropertySelectedAction)` используются для передачи колбэков на клик по тегу типа "Еще" и обычного тега соответственно
|
||||||
* после вызова конфигурационных методов обязательно необходимо вызать метод `build(FilterItem)`
|
* после вызова конфигурационных методов обязательно необходимо вызать метод `build()`
|
||||||
|
* в Builder необходимо передать объект `filterItem: FilterItem`
|
||||||
|
|
||||||
|
|
||||||
## 3. Выбор минимального и максимального значения из диапозона
|
## 3. Выбор минимального и максимального значения из диапозона
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,11 @@ dependencies {
|
||||||
|
|
||||||
implementation("androidx.appcompat:appcompat")
|
implementation("androidx.appcompat:appcompat")
|
||||||
implementation("com.google.android.material:material")
|
implementation("com.google.android.material:material")
|
||||||
implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha03")
|
implementation("androidx.constraintlayout:constraintlayout") {
|
||||||
|
version {
|
||||||
|
require '2.0.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constraints {
|
constraints {
|
||||||
implementation("androidx.appcompat:appcompat") {
|
implementation("androidx.appcompat:appcompat") {
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ import ru.touchin.roboswag.base_filters.select_list_item.adapter.SheetSelectionA
|
||||||
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
||||||
import ru.touchin.roboswag.base_filters.SelectionType
|
import ru.touchin.roboswag.base_filters.SelectionType
|
||||||
|
|
||||||
typealias OnSelectedItemListener<ItemType> = (item: ItemType) -> Unit
|
private typealias OnSelectedItemListener<ItemType> = (item: ItemType) -> Unit
|
||||||
typealias OnSelectedItemsListener<ItemType> = (items: List<ItemType>) -> Unit
|
private typealias OnSelectedItemsListener<ItemType> = (items: List<ItemType>) -> Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base [ListSelectionView] to use in filters screen for choosing single or multi items in list.
|
* Base [ListSelectionView] to use in filters screen for choosing single or multi items in list.
|
||||||
|
|
@ -26,7 +26,7 @@ typealias OnSelectedItemsListener<ItemType> = (items: List<ItemType>) -> Unit
|
||||||
* @param HolderType Type of viewHolder in recyclerView.
|
* @param HolderType Type of viewHolder in recyclerView.
|
||||||
* It must implement [BaseSelectionViewHolder] abstract class.
|
* It must implement [BaseSelectionViewHolder] abstract class.
|
||||||
*
|
*
|
||||||
**/
|
**/
|
||||||
|
|
||||||
class ListSelectionView<ItemType, HolderType> @JvmOverloads constructor(
|
class ListSelectionView<ItemType, HolderType> @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
|
@ -34,8 +34,8 @@ class ListSelectionView<ItemType, HolderType> @JvmOverloads constructor(
|
||||||
defStyleAttr: Int = 0,
|
defStyleAttr: Int = 0,
|
||||||
defStyleRes: Int = 0
|
defStyleRes: Int = 0
|
||||||
) : FrameLayout(context, attrs, defStyleAttr, defStyleRes)
|
) : FrameLayout(context, attrs, defStyleAttr, defStyleRes)
|
||||||
where ItemType: BaseSelectionItem,
|
where ItemType : BaseSelectionItem,
|
||||||
HolderType: BaseSelectionViewHolder<ItemType>{
|
HolderType : BaseSelectionViewHolder<ItemType> {
|
||||||
|
|
||||||
private var mutableItems: List<ItemType> = emptyList()
|
private var mutableItems: List<ItemType> = emptyList()
|
||||||
private var selectionType = SelectionType.SINGLE_SELECT
|
private var selectionType = SelectionType.SINGLE_SELECT
|
||||||
|
|
@ -83,37 +83,40 @@ class ListSelectionView<ItemType, HolderType> @JvmOverloads constructor(
|
||||||
updateList()
|
updateList()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setItems(items: List<ItemType>) = apply {
|
inner class Builder {
|
||||||
mutableItems = items
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> setItems(
|
fun setItems(items: List<ItemType>) = apply {
|
||||||
source: List<T>,
|
mutableItems = items
|
||||||
mapper: (T) -> ItemType
|
}
|
||||||
) = setItems(source.map { item -> mapper.invoke(item) })
|
|
||||||
|
|
||||||
fun showInHolder(holderFactory: HolderFactoryType<ItemType>) = apply {
|
fun <T> setItems(
|
||||||
factory = holderFactory
|
source: List<T>,
|
||||||
}
|
mapper: (T) -> ItemType
|
||||||
|
) = setItems(source.map { item -> mapper.invoke(item) })
|
||||||
|
|
||||||
fun addItemDecoration(itemDecoration: RecyclerView.ItemDecoration) = apply {
|
fun showInHolder(holderFactory: HolderFactoryType<ItemType>) = apply {
|
||||||
binding.itemsRecycler.addItemDecoration(itemDecoration)
|
factory = holderFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSelectedItemListener(listener: OnSelectedItemListener<ItemType>) = apply {
|
fun addItemDecoration(itemDecoration: RecyclerView.ItemDecoration) = apply {
|
||||||
this@ListSelectionView.onSelectedItemChanged = listener
|
binding.itemsRecycler.addItemDecoration(itemDecoration)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSelectedItemsListener(listener: OnSelectedItemsListener<ItemType>) = apply {
|
fun onSelectedItemListener(listener: OnSelectedItemListener<ItemType>) = apply {
|
||||||
this@ListSelectionView.onSelectedItemsChanged = listener
|
this@ListSelectionView.onSelectedItemChanged = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
fun withSelectionType(type: SelectionType) = apply {
|
fun onSelectedItemsListener(listener: OnSelectedItemsListener<ItemType>) = apply {
|
||||||
selectionType = type
|
this@ListSelectionView.onSelectedItemsChanged = listener
|
||||||
}
|
}
|
||||||
|
|
||||||
fun build() = apply {
|
fun withSelectionType(type: SelectionType) = apply {
|
||||||
binding.itemsRecycler.adapter = adapter
|
selectionType = type
|
||||||
updateList()
|
}
|
||||||
|
|
||||||
|
fun build() = this@ListSelectionView.also {
|
||||||
|
binding.itemsRecycler.adapter = adapter
|
||||||
|
updateList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import android.view.View
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
||||||
|
|
||||||
abstract class BaseSelectionViewHolder<ItemType: BaseSelectionItem>(val view: View)
|
abstract class BaseSelectionViewHolder<ItemType : BaseSelectionItem>(val view: View)
|
||||||
: RecyclerView.ViewHolder(view) {
|
: RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
abstract fun bind(item: ItemType)
|
abstract fun bind(item: ItemType)
|
||||||
|
|
|
||||||
|
|
@ -5,27 +5,29 @@ import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding
|
||||||
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
||||||
import ru.touchin.roboswag.base_filters.SelectionType
|
import ru.touchin.roboswag.base_filters.SelectionType
|
||||||
|
|
||||||
class SelectionItemViewHolder<ItemType: BaseSelectionItem>(private val binding: SelectionItemBinding,
|
class SelectionItemViewHolder<ItemType : BaseSelectionItem>(
|
||||||
private val onItemSelectAction: (ItemType) -> Unit,
|
private val binding: SelectionItemBinding,
|
||||||
private val selectionType: SelectionType
|
private val onItemSelectAction: (ItemType) -> Unit,
|
||||||
) : BaseSelectionViewHolder<ItemType>(binding.root) {
|
private val selectionType: SelectionType
|
||||||
|
) : BaseSelectionViewHolder<ItemType>(binding.root) {
|
||||||
|
|
||||||
override fun bind(item: ItemType) {
|
override fun bind(item: ItemType) {
|
||||||
binding.run {
|
binding.itemTitle.text = item.title
|
||||||
val checkListener = View.OnClickListener {
|
binding.itemRadiobutton.isChecked = item.isSelected
|
||||||
itemRadiobutton.isChecked = true
|
|
||||||
onItemSelectAction.invoke(item.copyWithSelection(isSelected = when (selectionType) {
|
|
||||||
SelectionType.SINGLE_SELECT -> true
|
|
||||||
else -> !item.isSelected
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
itemTitle.text = item.title
|
setupCheckListener(item)
|
||||||
root.setOnClickListener(checkListener)
|
}
|
||||||
|
|
||||||
itemRadiobutton.setOnClickListener(checkListener)
|
private fun setupCheckListener(item: ItemType) = with(binding) {
|
||||||
itemRadiobutton.isChecked = item.isSelected
|
val checkListener = View.OnClickListener {
|
||||||
|
itemRadiobutton.isChecked = true
|
||||||
|
onItemSelectAction.invoke(item.copyWithSelection(isSelected = when (selectionType) {
|
||||||
|
SelectionType.SINGLE_SELECT -> true
|
||||||
|
else -> !item.isSelected
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
root.setOnClickListener(checkListener)
|
||||||
|
itemRadiobutton.setOnClickListener(checkListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem
|
||||||
import ru.touchin.roboswag.base_filters.SelectionType
|
import ru.touchin.roboswag.base_filters.SelectionType
|
||||||
import ru.touchin.roboswag.recyclerview_adapters.adapters.DelegationListAdapter
|
import ru.touchin.roboswag.recyclerview_adapters.adapters.DelegationListAdapter
|
||||||
|
|
||||||
class SheetSelectionAdapter<ItemType: BaseSelectionItem>(
|
class SheetSelectionAdapter<ItemType : BaseSelectionItem>(
|
||||||
onItemSelectAction: (ItemType) -> Unit,
|
onItemSelectAction: (ItemType) -> Unit,
|
||||||
selectionType: SelectionType,
|
selectionType: SelectionType,
|
||||||
factory: HolderFactoryType<ItemType>
|
factory: HolderFactoryType<ItemType>
|
||||||
): DelegationListAdapter<BaseSelectionItem>(object : DiffUtil.ItemCallback<BaseSelectionItem>() {
|
) : DelegationListAdapter<BaseSelectionItem>(object : DiffUtil.ItemCallback<BaseSelectionItem>() {
|
||||||
|
|
||||||
override fun areItemsTheSame(oldItem: BaseSelectionItem, newItem: BaseSelectionItem): Boolean =
|
override fun areItemsTheSame(oldItem: BaseSelectionItem, newItem: BaseSelectionItem): Boolean =
|
||||||
oldItem.isItemTheSame(newItem)
|
oldItem.isItemTheSame(newItem)
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,5 @@ abstract class BaseSelectionItem(
|
||||||
|
|
||||||
abstract fun isContentTheSame(compareItem: BaseSelectionItem): Boolean
|
abstract fun isContentTheSame(compareItem: BaseSelectionItem): Boolean
|
||||||
|
|
||||||
abstract fun <ItemType>copyWithSelection(isSelected: Boolean): ItemType
|
abstract fun <ItemType> copyWithSelection(isSelected: Boolean): ItemType
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,13 @@ package ru.touchin.roboswag.base_filters.tags
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.LayoutRes
|
import androidx.annotation.LayoutRes
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import com.google.android.material.chip.ChipGroup
|
import com.google.android.material.chip.ChipGroup
|
||||||
import ru.touchin.roboswag.base_filters.R
|
import ru.touchin.roboswag.base_filters.R
|
||||||
import ru.touchin.roboswag.base_filters.SelectionType
|
import ru.touchin.roboswag.base_filters.SelectionType
|
||||||
import ru.touchin.roboswag.base_filters.databinding.TagSelectionLayoutBinding
|
|
||||||
import ru.touchin.roboswag.base_filters.tags.model.FilterItem
|
import ru.touchin.roboswag.base_filters.tags.model.FilterItem
|
||||||
import ru.touchin.roboswag.base_filters.tags.model.FilterProperty
|
import ru.touchin.roboswag.base_filters.tags.model.FilterProperty
|
||||||
import ru.touchin.roboswag.components.utils.UiUtils
|
import ru.touchin.roboswag.components.utils.UiUtils
|
||||||
|
|
@ -27,10 +24,9 @@ class TagLayoutView @JvmOverloads constructor(
|
||||||
defStyleAttr: Int = 0
|
defStyleAttr: Int = 0
|
||||||
) : FrameLayout(context, attrs, defStyleAttr) {
|
) : FrameLayout(context, attrs, defStyleAttr) {
|
||||||
|
|
||||||
private val binding = TagSelectionLayoutBinding.inflate(LayoutInflater.from(context), this)
|
|
||||||
private var filterItem: FilterItem by Delegates.notNull()
|
private var filterItem: FilterItem by Delegates.notNull()
|
||||||
|
|
||||||
private var tagsContainer: ChipGroup = binding.multiLineTagGroup
|
private var tagsContainer: ChipGroup by Delegates.notNull()
|
||||||
|
|
||||||
private var propertySelectedAction: PropertySelectedAction? = null
|
private var propertySelectedAction: PropertySelectedAction? = null
|
||||||
private var moreValuesAction: FilterMoreAction? = null
|
private var moreValuesAction: FilterMoreAction? = null
|
||||||
|
|
@ -44,82 +40,16 @@ class TagLayoutView @JvmOverloads constructor(
|
||||||
private var tagLayout: Int = R.layout.layout_default_tag
|
private var tagLayout: Int = R.layout.layout_default_tag
|
||||||
|
|
||||||
private var moreTagText: String = ""
|
private var moreTagText: String = ""
|
||||||
private var maxTagCount: Int? = null
|
private var maxTagCount = Int.MAX_VALUE
|
||||||
|
|
||||||
@LayoutRes
|
@LayoutRes
|
||||||
private var moreTagLayout: Int? = null
|
private var moreTagLayout: Int = tagLayout
|
||||||
|
|
||||||
fun onMoreValuesAction(action: FilterMoreAction) = apply {
|
private fun inflateAndGetChipGroup(isSingleLine: Boolean): ChipGroup {
|
||||||
moreValuesAction = action
|
val layoutId = if (isSingleLine) R.layout.layout_single_line_tag_group else R.layout.layout_multi_line_tag_group
|
||||||
}
|
return UiUtils.inflate(layoutId, this)
|
||||||
|
.also { addView(it) }
|
||||||
fun onPropertySelectedAction(action: PropertySelectedAction) = apply {
|
.findViewById(R.id.tag_group)
|
||||||
propertySelectedAction = action
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setMaxTagCount(count: Int) = apply {
|
|
||||||
maxTagCount = count
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSpacingHorizontal(horizontalSpacingDp: Int) = apply {
|
|
||||||
tagSpacingHorizontalDp = horizontalSpacingDp
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSpacingVertical(verticalSpacingDp: Int) = apply {
|
|
||||||
tagSpacingVerticalDp = verticalSpacingDp
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSpacing(value: Int) = apply {
|
|
||||||
tagSpacingHorizontalDp = value
|
|
||||||
tagSpacingVerticalDp = value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setSelectionType(type: SelectionType) = apply {
|
|
||||||
selectionType = type
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isSingleLine(value: Boolean) = apply {
|
|
||||||
isSingleLine = value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setTagLayout(@LayoutRes layoutId: Int) = apply {
|
|
||||||
tagLayout = layoutId
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setMoreTagLayout(@LayoutRes layoutId: Int, text: String) = apply {
|
|
||||||
moreTagLayout = layoutId
|
|
||||||
moreTagText = text
|
|
||||||
}
|
|
||||||
|
|
||||||
fun build(filterItem: FilterItem) {
|
|
||||||
this.filterItem = filterItem
|
|
||||||
tagsContainer = getTagView(isSingleLine)
|
|
||||||
|
|
||||||
with(tagsContainer) {
|
|
||||||
removeAllViews()
|
|
||||||
|
|
||||||
this.isSingleLine = isSingleLine
|
|
||||||
|
|
||||||
chipSpacingHorizontal = tagSpacingHorizontalDp.px
|
|
||||||
chipSpacingVertical = tagSpacingVerticalDp.px
|
|
||||||
|
|
||||||
val properties = maxTagCount
|
|
||||||
?.let { count -> filterItem.properties.take(count) }
|
|
||||||
?: filterItem.properties
|
|
||||||
properties.forEach { property ->
|
|
||||||
addView(createTag(property))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxTagCount != null && filterItem.properties.size > maxTagCount!!) {
|
|
||||||
createMoreChip(filterItem)?.let { addView(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getTagView(isSingleLine: Boolean): ChipGroup {
|
|
||||||
binding.lineTagContainer.isVisible = isSingleLine
|
|
||||||
binding.multiLineTagGroup.isVisible = !isSingleLine
|
|
||||||
return if (isSingleLine) binding.singleLineTagGroup else binding.multiLineTagGroup
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createTag(property: FilterProperty): TagView =
|
private fun createTag(property: FilterProperty): TagView =
|
||||||
|
|
@ -138,12 +68,11 @@ class TagLayoutView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
} ?: throw IllegalArgumentException("Layout for tag must be extended from TagView")
|
} ?: throw IllegalArgumentException("Layout for tag must be extended from TagView")
|
||||||
|
|
||||||
private fun createMoreChip(filter: FilterItem): View? = moreTagLayout?.let {
|
private fun createMoreChip(filter: FilterItem): View? =
|
||||||
(UiUtils.inflate(it, this) as? TextView)?.apply {
|
(UiUtils.inflate(moreTagLayout, this) as? TextView)?.apply {
|
||||||
text = moreTagText
|
text = moreTagText
|
||||||
setOnClickListener { moreValuesAction?.invoke(filter) }
|
setOnClickListener { moreValuesAction?.invoke(filter) }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearCheck(selectedId: Int) {
|
private fun clearCheck(selectedId: Int) {
|
||||||
for (i in 0 until tagsContainer.childCount) {
|
for (i in 0 until tagsContainer.childCount) {
|
||||||
|
|
@ -164,4 +93,71 @@ class TagLayoutView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inner class Builder(private val filterItem: FilterItem) {
|
||||||
|
|
||||||
|
fun onMoreValuesAction(action: FilterMoreAction) = apply {
|
||||||
|
moreValuesAction = action
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onPropertySelectedAction(action: PropertySelectedAction) = apply {
|
||||||
|
propertySelectedAction = action
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMaxTagCount(count: Int) = apply {
|
||||||
|
maxTagCount = count
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSpacingHorizontal(horizontalSpacingDp: Int) = apply {
|
||||||
|
tagSpacingHorizontalDp = horizontalSpacingDp
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSpacingVertical(verticalSpacingDp: Int) = apply {
|
||||||
|
tagSpacingVerticalDp = verticalSpacingDp
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSpacing(value: Int) = apply {
|
||||||
|
tagSpacingHorizontalDp = value
|
||||||
|
tagSpacingVerticalDp = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSelectionType(type: SelectionType) = apply {
|
||||||
|
selectionType = type
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isSingleLine(value: Boolean) = apply {
|
||||||
|
isSingleLine = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTagLayout(@LayoutRes layoutId: Int) = apply {
|
||||||
|
tagLayout = layoutId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setMoreTagLayout(@LayoutRes layoutId: Int, text: String) = apply {
|
||||||
|
moreTagLayout = layoutId
|
||||||
|
moreTagText = text
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build() {
|
||||||
|
this@TagLayoutView.filterItem = filterItem
|
||||||
|
tagsContainer = inflateAndGetChipGroup(isSingleLine)
|
||||||
|
|
||||||
|
with(tagsContainer) {
|
||||||
|
removeAllViews()
|
||||||
|
|
||||||
|
this.isSingleLine = isSingleLine
|
||||||
|
|
||||||
|
chipSpacingHorizontal = tagSpacingHorizontalDp.px
|
||||||
|
chipSpacingVertical = tagSpacingVerticalDp.px
|
||||||
|
|
||||||
|
filterItem.properties.take(maxTagCount).forEach { property ->
|
||||||
|
addView(createTag(property))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterItem.properties.size > maxTagCount) {
|
||||||
|
createMoreChip(filterItem)?.let { addView(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/tag_group"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:chipSpacing="8dp"
|
||||||
|
app:selectionRequired="false"
|
||||||
|
app:singleLine="false"
|
||||||
|
app:singleSelection="true" />
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<HorizontalScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/line_tag_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/tag_group"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:selectionRequired="true" />
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<merge
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
|
||||||
android:id="@+id/multi_line_tag_group"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:selectionRequired="false"
|
|
||||||
app:singleLine="false"
|
|
||||||
app:singleSelection="true"
|
|
||||||
app:chipSpacing="8dp"/>
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
|
||||||
android:id="@+id/line_tag_container"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clipToPadding="false"
|
|
||||||
android:scrollbars="none"
|
|
||||||
android:visibility="gone">
|
|
||||||
|
|
||||||
<com.google.android.material.chip.ChipGroup
|
|
||||||
android:id="@+id/single_line_tag_group"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:selectionRequired="true"/>
|
|
||||||
|
|
||||||
</HorizontalScrollView>
|
|
||||||
|
|
||||||
</merge>
|
|
||||||
|
|
@ -7,10 +7,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Widget.FilterSelection.Item" parent="@style/Widget.MaterialComponents.TextView">
|
<style name="Widget.FilterSelection.Item" parent="@style/Widget.MaterialComponents.TextView">
|
||||||
<item name="android:layout_marginStart">16dp</item>
|
<item name="android:layout_margin">16dp</item>
|
||||||
<item name="android:layout_marginEnd">16dp</item>
|
|
||||||
<item name="android:layout_marginTop">16dp</item>
|
|
||||||
<item name="android:layout_marginBottom">16dp</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Widget.FilterSelection.Radio" parent="@style/Widget.MaterialComponents.CompoundButton.RadioButton">
|
<style name="Widget.FilterSelection.Radio" parent="@style/Widget.MaterialComponents.CompoundButton.RadioButton">
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue