From aad4c398e820b990857ce932755b75e728367624 Mon Sep 17 00:00:00 2001 From: AnastasiyaK97 Date: Wed, 27 Jul 2022 15:54:02 +0300 Subject: [PATCH 1/8] add base-filter module --- base-filters/.gitignore | 1 + base-filters/build.gradle | 23 +++++++++++++++++++++++ base-filters/src/main/AndroidManifest.xml | 2 ++ 3 files changed, 26 insertions(+) create mode 100644 base-filters/.gitignore create mode 100644 base-filters/build.gradle create mode 100644 base-filters/src/main/AndroidManifest.xml diff --git a/base-filters/.gitignore b/base-filters/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/base-filters/.gitignore @@ -0,0 +1 @@ +/build diff --git a/base-filters/build.gradle b/base-filters/build.gradle new file mode 100644 index 0000000..65ea18b --- /dev/null +++ b/base-filters/build.gradle @@ -0,0 +1,23 @@ +apply from: "../android-configs/lib-config.gradle" + +dependencies { + implementation("org.jetbrains.kotlin:kotlin-stdlib") + + implementation("androidx.core:core-ktx") + + implementation("androidx.appcompat:appcompat") + + constraints { + implementation("androidx.appcompat:appcompat") { + version { + require '1.0.0' + } + } + + implementation("androidx.core:core-ktx") { + version { + require '1.0.0' + } + } + } +} diff --git a/base-filters/src/main/AndroidManifest.xml b/base-filters/src/main/AndroidManifest.xml new file mode 100644 index 0000000..47d581d --- /dev/null +++ b/base-filters/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + From eb9d4adcf20d85858ddf3049eb316068d6a369f6 Mon Sep 17 00:00:00 2001 From: AnastasiyaK97 Date: Thu, 28 Jul 2022 19:54:04 +0300 Subject: [PATCH 2/8] =?UTF-8?q?INTERNAL-300=20+=20INTERNAL-299:=20=D0=94?= =?UTF-8?q?=D0=BE=D0=B1=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BD=D0=B0=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=B0=D0=B8=D0=B2=D0=B0=D0=B5=D0=BC=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=B2=D1=8C=D1=8E=20=D1=81=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BE=D0=BC=20=D0=BE=D0=B4=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=B8?= =?UTF-8?q?=D0=BB=D0=B8=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB=D1=8C=D0=BA?= =?UTF-8?q?=D0=B8=D1=85=20=D0=B2=D0=B0=D1=80=D0=B8=D0=B0=D0=BD=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=B8=D0=B7=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base-filters/build.gradle | 14 ++++ base-filters/src/main/AndroidManifest.xml | 2 +- .../select_list_item/ListSelectionView.kt | 83 +++++++++++++++++++ .../adapter/SheetSelectionAdapter.kt | 24 ++++++ .../adapter/SheetSelectionDelegate.kt | 47 +++++++++++ .../model/RowSelectionItem.kt | 11 +++ .../src/main/res/layout/selection_item.xml | 29 +++++++ .../res/layout/single_selection_layout.xml | 10 +++ base-filters/src/main/res/values/attrs.xml | 9 ++ base-filters/src/main/res/values/styles.xml | 21 +++++ 10 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt create mode 100644 base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt create mode 100644 base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt create mode 100644 base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/RowSelectionItem.kt create mode 100644 base-filters/src/main/res/layout/selection_item.xml create mode 100644 base-filters/src/main/res/layout/single_selection_layout.xml create mode 100644 base-filters/src/main/res/values/attrs.xml create mode 100644 base-filters/src/main/res/values/styles.xml diff --git a/base-filters/build.gradle b/base-filters/build.gradle index 65ea18b..a8904a1 100644 --- a/base-filters/build.gradle +++ b/base-filters/build.gradle @@ -1,11 +1,25 @@ apply from: "../android-configs/lib-config.gradle" +apply plugin: 'kotlin-parcelize' + +android { + buildFeatures { + viewBinding true + } +} dependencies { + implementation project(":utils") + implementation project(":recyclerview-adapters") + implementation project(":navigation-base") + implementation project(":kotlin-extensions") + implementation("org.jetbrains.kotlin:kotlin-stdlib") implementation("androidx.core:core-ktx") implementation("androidx.appcompat:appcompat") + implementation("com.google.android.material:material") + implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha03") constraints { implementation("androidx.appcompat:appcompat") { diff --git a/base-filters/src/main/AndroidManifest.xml b/base-filters/src/main/AndroidManifest.xml index 47d581d..14e5b35 100644 --- a/base-filters/src/main/AndroidManifest.xml +++ b/base-filters/src/main/AndroidManifest.xml @@ -1,2 +1,2 @@ + package="ru.touchin.roboswag.base_filters"/> diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt new file mode 100644 index 0000000..8e30fc8 --- /dev/null +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt @@ -0,0 +1,83 @@ +package ru.touchin.roboswag.base_filters.select_list_item + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import android.widget.FrameLayout +import androidx.recyclerview.widget.RecyclerView +import ru.touchin.roboswag.base_filters.databinding.SingleSelectionLayoutBinding +import ru.touchin.roboswag.base_filters.select_list_item.adapter.SheetSelectionAdapter +import ru.touchin.roboswag.base_filters.select_list_item.model.RowSelectionItem + +typealias OnItemSelectedListener = (item: RowSelectionItem) -> Unit +typealias OnSelectionResultListener = (items: List) -> Unit + +class ListSelectionView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) { + + private var mutableItems: List = emptyList() + private var selectionType = SelectionType.SINGLE_SELECT + + private var onItemsClickListener: OnSelectionResultListener? = null + private var onItemClickListener: OnItemSelectedListener? = null + + private val binding = SingleSelectionLayoutBinding.inflate(LayoutInflater.from(context), this, true) + + private val adapter by lazy { + SheetSelectionAdapter(onItemSelectAction = onItemSelectedListener) + } + + private val onItemSelectedListener: OnItemSelectedListener = { item -> + onItemClickListener?.invoke(item) + updateAfterSelection(item) + onItemsClickListener?.invoke(mutableItems) + } + + private fun updateList() { + adapter.submitList(mutableItems) + } + + private fun updateAfterSelection(selectedItem: RowSelectionItem) { + mutableItems = mutableItems.map { item -> + when { + item.id == selectedItem.id -> selectedItem + selectionType == SelectionType.SINGLE_SELECT -> item.copy(isSelected = false) + else -> item + } + } + updateList() + } + + fun setItems(items: List) = apply { + binding.itemsRecycler.adapter = adapter + mutableItems = items + updateList() + } + + fun setItems( + source: List, + mapper: (T) -> RowSelectionItem + ) = setItems(source.map { item -> mapper.invoke(item) }) + + fun addItemDecoration(itemDecoration: RecyclerView.ItemDecoration) = apply { + binding.itemsRecycler.addItemDecoration(itemDecoration) + } + + fun onItemClickListener(listener: OnItemSelectedListener) = apply { + this@ListSelectionView.onItemClickListener = listener + } + + fun onResultListener(listener: OnSelectionResultListener) = apply { + this@ListSelectionView.onItemsClickListener = listener + } + + fun withSelectionType(type: SelectionType) = apply { + selectionType = type + } + + enum class SelectionType { SINGLE_SELECT, MULTI_SELECT } +} diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt new file mode 100644 index 0000000..6b92b5a --- /dev/null +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt @@ -0,0 +1,24 @@ +package ru.touchin.roboswag.base_filters.select_list_item.adapter + +import androidx.recyclerview.widget.DiffUtil +import ru.touchin.roboswag.base_filters.select_list_item.OnItemSelectedListener +import ru.touchin.roboswag.base_filters.select_list_item.model.RowSelectionItem +import ru.touchin.roboswag.recyclerview_adapters.adapters.DelegationListAdapter + +class SheetSelectionAdapter( + onItemSelectAction: OnItemSelectedListener +): DelegationListAdapter(object : DiffUtil.ItemCallback() { + + override fun areItemsTheSame(oldItem: RowSelectionItem, newItem: RowSelectionItem): Boolean = + oldItem.id == newItem.id + + override fun areContentsTheSame(oldItem: RowSelectionItem, newItem: RowSelectionItem): Boolean = + oldItem == newItem + +}) { + + init { + addDelegate(SheetSelectionDelegate(onItemSelectAction)) + } + +} diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt new file mode 100644 index 0000000..4dbfa35 --- /dev/null +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt @@ -0,0 +1,47 @@ +package ru.touchin.roboswag.base_filters.select_list_item.adapter + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding +import ru.touchin.roboswag.base_filters.select_list_item.OnItemSelectedListener +import ru.touchin.roboswag.base_filters.select_list_item.model.RowSelectionItem +import ru.touchin.roboswag.recyclerview_adapters.adapters.ItemAdapterDelegate + +class SheetSelectionDelegate( + private val onItemSelectAction: OnItemSelectedListener +) : ItemAdapterDelegate() { + + override fun onCreateViewHolder(parent: ViewGroup): SelectionItemViewHolder = SelectionItemViewHolder( + binding = SelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) + ) + + override fun onBindViewHolder( + holder: SelectionItemViewHolder, + item: RowSelectionItem, + adapterPosition: Int, + collectionPosition: Int, + payloads: MutableList + ) = holder.bind(item) + + inner class SelectionItemViewHolder(val binding: SelectionItemBinding) : RecyclerView.ViewHolder(binding.root) { + + fun bind(item: RowSelectionItem) { + binding.run { + val checkListener = View.OnClickListener { + itemRadiobutton.isChecked = true + onItemSelectAction.invoke(item.copy(isSelected = !item.isSelected)) + } + + itemTitle.text = item.title + root.setOnClickListener(checkListener) + + itemRadiobutton.setOnClickListener(checkListener) + itemRadiobutton.isChecked = item.isSelected + } + } + + } + +} diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/RowSelectionItem.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/RowSelectionItem.kt new file mode 100644 index 0000000..007eb69 --- /dev/null +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/RowSelectionItem.kt @@ -0,0 +1,11 @@ +package ru.touchin.roboswag.base_filters.select_list_item.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class RowSelectionItem( + val id: Int, + val title: String, + val isSelected: Boolean = false +): Parcelable diff --git a/base-filters/src/main/res/layout/selection_item.xml b/base-filters/src/main/res/layout/selection_item.xml new file mode 100644 index 0000000..72bb7eb --- /dev/null +++ b/base-filters/src/main/res/layout/selection_item.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/base-filters/src/main/res/layout/single_selection_layout.xml b/base-filters/src/main/res/layout/single_selection_layout.xml new file mode 100644 index 0000000..2db23f9 --- /dev/null +++ b/base-filters/src/main/res/layout/single_selection_layout.xml @@ -0,0 +1,10 @@ + + diff --git a/base-filters/src/main/res/values/attrs.xml b/base-filters/src/main/res/values/attrs.xml new file mode 100644 index 0000000..bd6618a --- /dev/null +++ b/base-filters/src/main/res/values/attrs.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/base-filters/src/main/res/values/styles.xml b/base-filters/src/main/res/values/styles.xml new file mode 100644 index 0000000..3520002 --- /dev/null +++ b/base-filters/src/main/res/values/styles.xml @@ -0,0 +1,21 @@ + + + + + + + + + + From d08800af46e4a72a84ded333fa6c35711cb0385d Mon Sep 17 00:00:00 2001 From: AnastasiyaK97 Date: Fri, 29 Jul 2022 12:41:30 +0300 Subject: [PATCH 3/8] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20readme=20=D1=84=D0=B0=D0=B9=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base-filters/README.md | 70 +++++++++++++++++++ .../select_list_item/ListSelectionView.kt | 12 +++- .../adapter/SheetSelectionAdapter.kt | 6 +- .../adapter/SheetSelectionDelegate.kt | 10 ++- 4 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 base-filters/README.md diff --git a/base-filters/README.md b/base-filters/README.md new file mode 100644 index 0000000..cb6175b --- /dev/null +++ b/base-filters/README.md @@ -0,0 +1,70 @@ +# Описание + +Модуль содержит реализацию следующих типов фильтров: + +1. Выбор одного из доступных значений списка +2. Выбор нескольких доступных значений из списка +3. добавить остальные по ходу реализаации + +# Использование + +## Выбор одного/нескольких из доступных значений списка + +### Как использовать +``` kotlin +val selectorView = ListSelectionView(context) + .setItems(navArgs.items) + .addItemDecoration((TopDividerItemDecoration( + context = requireContext(), + drawableId = R.drawable.list_divider_1dp, + startMargin = START_MARGIN_DIVIDER_DP.px + ))) + .withSelectionType(ListSelectionView.SelectionType.SINGLE_SELECT) + .onResultListener { items -> + viewModel.dispatchAction(SelectItemAction.SelectItem(items)) } + .build() +``` +### Конфигурации +* в метод `setItems(List)` необходимо передать список объектов +* метод `addItemDecoration()` можно использовать для передачи объекта `RecyclerView.ItemDecoration` +* метод `withSelectionType()` используется для указания типа выбора: + * `SINGLE_SELECT` - по умолчанию - позволяет выбрать один выариант, при этом будет выбран всегда как минимум один вариант + * `MULTI_SELECT` - позволяет выбрать несколько вариантов из списка, при этом можно полностью выбрать все варианты и убрать выделение со всех вариантов +* колбэк `onResultListener()` можно использовать для получения списка всех элементов `RowSelectionItem` после каждого выбора +* колбэк `onItemClickListener()` можно использовать для получения элемента списка `RowSelectionItem`, по которому произошел клик +* после вызова конфигурационных методов обязательно необходимо вызать метод `build()` + +### Кастомизация стиля + +#### 1. Определить кастомную тему и стили элементов +1. Стиль для **текста элемента списка** должен быть наследником стиля `Widget.FilterSelection.Item` +``` xml + +``` +2. Стиль для **индикатора выбора** должен быть наследником стиля `Widget.FilterSelection.Radio` +Передайте `selector-drawable` для кастомизации вида индикатора в конце строки +``` xml + +``` +3. Создайте **тему**, которая должна быть наследником `Theme.FilterSelection` +``` xml + +``` +#### 2. Применить тему при создании view +При создании вью в коде можно указать тему, используя `ContextThemeWrapper` +``` kotlin +val newContext = ContextThemeWrapper(requireContext(), R.style.Theme_Custom_FilterSelection) +val selectorView = ListSelectionView(newContext) + ... + .build() +``` diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt index 8e30fc8..f217c65 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt @@ -28,7 +28,10 @@ class ListSelectionView @JvmOverloads constructor( private val binding = SingleSelectionLayoutBinding.inflate(LayoutInflater.from(context), this, true) private val adapter by lazy { - SheetSelectionAdapter(onItemSelectAction = onItemSelectedListener) + SheetSelectionAdapter( + onItemSelectAction = onItemSelectedListener, + selectionType = selectionType + ) } private val onItemSelectedListener: OnItemSelectedListener = { item -> @@ -53,9 +56,7 @@ class ListSelectionView @JvmOverloads constructor( } fun setItems(items: List) = apply { - binding.itemsRecycler.adapter = adapter mutableItems = items - updateList() } fun setItems( @@ -79,5 +80,10 @@ class ListSelectionView @JvmOverloads constructor( selectionType = type } + fun build() = apply { + binding.itemsRecycler.adapter = adapter + updateList() + } + enum class SelectionType { SINGLE_SELECT, MULTI_SELECT } } diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt index 6b92b5a..93fadef 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt @@ -1,12 +1,14 @@ package ru.touchin.roboswag.base_filters.select_list_item.adapter import androidx.recyclerview.widget.DiffUtil +import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView import ru.touchin.roboswag.base_filters.select_list_item.OnItemSelectedListener import ru.touchin.roboswag.base_filters.select_list_item.model.RowSelectionItem import ru.touchin.roboswag.recyclerview_adapters.adapters.DelegationListAdapter class SheetSelectionAdapter( - onItemSelectAction: OnItemSelectedListener + onItemSelectAction: OnItemSelectedListener, + selectionType: ListSelectionView.SelectionType ): DelegationListAdapter(object : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: RowSelectionItem, newItem: RowSelectionItem): Boolean = @@ -18,7 +20,7 @@ class SheetSelectionAdapter( }) { init { - addDelegate(SheetSelectionDelegate(onItemSelectAction)) + addDelegate(SheetSelectionDelegate(onItemSelectAction, selectionType)) } } diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt index 4dbfa35..31982ba 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt @@ -5,12 +5,15 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding +import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView +import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView.SelectionType import ru.touchin.roboswag.base_filters.select_list_item.OnItemSelectedListener import ru.touchin.roboswag.base_filters.select_list_item.model.RowSelectionItem import ru.touchin.roboswag.recyclerview_adapters.adapters.ItemAdapterDelegate class SheetSelectionDelegate( - private val onItemSelectAction: OnItemSelectedListener + private val onItemSelectAction: OnItemSelectedListener, + private val selectionType: ListSelectionView.SelectionType ) : ItemAdapterDelegate() { override fun onCreateViewHolder(parent: ViewGroup): SelectionItemViewHolder = SelectionItemViewHolder( @@ -31,7 +34,10 @@ class SheetSelectionDelegate( binding.run { val checkListener = View.OnClickListener { itemRadiobutton.isChecked = true - onItemSelectAction.invoke(item.copy(isSelected = !item.isSelected)) + onItemSelectAction.invoke(item.copy(isSelected = when (selectionType) { + SelectionType.SINGLE_SELECT -> true + else -> !item.isSelected + })) } itemTitle.text = item.title From 719252a3e182df32333893fcf2483aac39787b01 Mon Sep 17 00:00:00 2001 From: AnastasiyaK97 Date: Mon, 1 Aug 2022 11:37:49 +0300 Subject: [PATCH 4/8] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B2=D0=BE=D0=B7=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D0=B2=20=D1=81=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=BA=D0=B5=20=D0=BA=D0=B0=D1=81=D1=82=D0=BE=D0=BC=D0=BD?= =?UTF-8?q?=D1=83=D1=8E=20=D1=80=D0=B0=D0=B7=D0=BC=D0=B5=D1=82=D0=BA=D1=83?= =?UTF-8?q?=20=D0=B8=20=D1=82=D0=B8=D0=BF=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base-filters/README.md | 29 ++++++-- .../select_list_item/ListSelectionView.kt | 73 +++++++++++++------ .../adapter/BaseSelectionViewHolder.kt | 11 +++ .../adapter/SheetSelectionAdapter.kt | 26 ++++--- .../adapter/SheetSelectionDelegate.kt | 63 ++++++++-------- .../model/BaseSelectionItem.kt | 14 ++++ .../model/DefaultSelectionItem.kt | 24 ++++++ .../model/RowSelectionItem.kt | 11 --- 8 files changed, 171 insertions(+), 80 deletions(-) create mode 100644 base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/BaseSelectionViewHolder.kt create mode 100644 base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/BaseSelectionItem.kt create mode 100644 base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/DefaultSelectionItem.kt delete mode 100644 base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/RowSelectionItem.kt diff --git a/base-filters/README.md b/base-filters/README.md index cb6175b..09d83de 100644 --- a/base-filters/README.md +++ b/base-filters/README.md @@ -12,7 +12,7 @@ ### Как использовать ``` kotlin -val selectorView = ListSelectionView(context) +val selectorView = ListSelectionView>(context) .setItems(navArgs.items) .addItemDecoration((TopDividerItemDecoration( context = requireContext(), @@ -25,16 +25,31 @@ val selectorView = ListSelectionView(context) .build() ``` ### Конфигурации -* в метод `setItems(List)` необходимо передать список объектов -* метод `addItemDecoration()` можно использовать для передачи объекта `RecyclerView.ItemDecoration` -* метод `withSelectionType()` используется для указания типа выбора: +* при создании `ListSelectionView` необходимо передлать `ItemType` - класс модели данных в списке, `HolderType` - класс viewHolder-а в recyclerView. +Для использования дефолтной реализации необходимо использовать типы `>` +* в метод `setItems(List)` необходимо передать список объектов +* метод `addItemDecoration(itemDecoration: RecyclerView.ItemDecoration)` можно использовать для передачи объекта `RecyclerView.ItemDecoration` +* метод `withSelectionType(type: SelectionType)` используется для указания типа выбора: * `SINGLE_SELECT` - по умолчанию - позволяет выбрать один выариант, при этом будет выбран всегда как минимум один вариант * `MULTI_SELECT` - позволяет выбрать несколько вариантов из списка, при этом можно полностью выбрать все варианты и убрать выделение со всех вариантов -* колбэк `onResultListener()` можно использовать для получения списка всех элементов `RowSelectionItem` после каждого выбора -* колбэк `onItemClickListener()` можно использовать для получения элемента списка `RowSelectionItem`, по которому произошел клик +* метод `showInHolder(HolderFactoryType)` используется для определения кастомного viewHolder для списка с недефолтной разметкой. +``` kotlin +val selectorView = ListSelectionView(context) + .showInHolder { parent, clickListener, selectionType -> + TestItemViewHolder( + binding = TestSelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false), + onItemSelectAction = clickListener, + selectionType = selectionType + ) + } + ... + .build() +``` +* колбэк `onSelectedItemsListener(listener: OnSelectedItemsListener)` можно использовать для получения списка всех элементов `ItemType` после каждого выбора +* колбэк `onSelectedItemListener(listener: OnSelectedItemListener)` можно использовать для получения элемента списка `ItemType`, по которому произошел клик * после вызова конфигурационных методов обязательно необходимо вызать метод `build()` -### Кастомизация стиля +### Кастомизация стиля дефолтной реализации ViewHolder без необходимости создания кастомного layout и viewHolder #### 1. Определить кастомную тему и стили элементов 1. Стиль для **текста элемента списка** должен быть наследником стиля `Widget.FilterSelection.Item` diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt index f217c65..e095ada 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt @@ -5,75 +5,106 @@ import android.util.AttributeSet import android.view.LayoutInflater import android.widget.FrameLayout import androidx.recyclerview.widget.RecyclerView +import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding import ru.touchin.roboswag.base_filters.databinding.SingleSelectionLayoutBinding +import ru.touchin.roboswag.base_filters.select_list_item.adapter.BaseSelectionViewHolder +import ru.touchin.roboswag.base_filters.select_list_item.adapter.HolderFactoryType +import ru.touchin.roboswag.base_filters.select_list_item.adapter.SelectionItemViewHolder import ru.touchin.roboswag.base_filters.select_list_item.adapter.SheetSelectionAdapter -import ru.touchin.roboswag.base_filters.select_list_item.model.RowSelectionItem +import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem -typealias OnItemSelectedListener = (item: RowSelectionItem) -> Unit -typealias OnSelectionResultListener = (items: List) -> Unit +typealias OnSelectedItemListener = (item: ItemType) -> Unit +typealias OnSelectedItemsListener = (items: List) -> Unit -class ListSelectionView @JvmOverloads constructor( +/** + * Base [ListSelectionView] to use in filters screen for choosing single or multi items in list. + * + * @param ItemType Type of model's element in list. + * It must implement [BaseSelectionItem] abstract class. + * + * @param HolderType Type of viewHolder in recyclerView. + * It must implement [BaseSelectionViewHolder] abstract class. + * +**/ + +class ListSelectionView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 -) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) { +) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) + where ItemType: BaseSelectionItem, + HolderType: BaseSelectionViewHolder{ - private var mutableItems: List = emptyList() + private var mutableItems: List = emptyList() private var selectionType = SelectionType.SINGLE_SELECT - private var onItemsClickListener: OnSelectionResultListener? = null - private var onItemClickListener: OnItemSelectedListener? = null + private var onSelectedItemChanged: OnSelectedItemListener? = null + private var onSelectedItemsChanged: OnSelectedItemsListener? = null + private var factory: HolderFactoryType = getDefaultFactory() + + private fun getDefaultFactory(): HolderFactoryType = { parent, clickListener, selectionType -> + SelectionItemViewHolder( + binding = SelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false), + onItemSelectAction = clickListener, + selectionType = selectionType + ) + } private val binding = SingleSelectionLayoutBinding.inflate(LayoutInflater.from(context), this, true) private val adapter by lazy { SheetSelectionAdapter( onItemSelectAction = onItemSelectedListener, - selectionType = selectionType + selectionType = selectionType, + factory = factory ) } - private val onItemSelectedListener: OnItemSelectedListener = { item -> - onItemClickListener?.invoke(item) + private val onItemSelectedListener: (item: ItemType) -> Unit = { item -> + onSelectedItemChanged?.invoke(item) updateAfterSelection(item) - onItemsClickListener?.invoke(mutableItems) + onSelectedItemsChanged?.invoke(mutableItems) } private fun updateList() { adapter.submitList(mutableItems) } - private fun updateAfterSelection(selectedItem: RowSelectionItem) { + private fun updateAfterSelection(selectedItem: ItemType) { mutableItems = mutableItems.map { item -> when { - item.id == selectedItem.id -> selectedItem - selectionType == SelectionType.SINGLE_SELECT -> item.copy(isSelected = false) + item.isItemTheSame(selectedItem) -> selectedItem + selectionType == SelectionType.SINGLE_SELECT -> item.copyWithSelection(isSelected = false) else -> item } } updateList() } - fun setItems(items: List) = apply { + fun setItems(items: List) = apply { mutableItems = items } fun setItems( source: List, - mapper: (T) -> RowSelectionItem + mapper: (T) -> ItemType ) = setItems(source.map { item -> mapper.invoke(item) }) + fun showInHolder(holderFactory: HolderFactoryType) = apply { + factory = holderFactory + } + fun addItemDecoration(itemDecoration: RecyclerView.ItemDecoration) = apply { binding.itemsRecycler.addItemDecoration(itemDecoration) } - fun onItemClickListener(listener: OnItemSelectedListener) = apply { - this@ListSelectionView.onItemClickListener = listener + fun onSelectedItemListener(listener: OnSelectedItemListener) = apply { + this@ListSelectionView.onSelectedItemChanged = listener } - fun onResultListener(listener: OnSelectionResultListener) = apply { - this@ListSelectionView.onItemsClickListener = listener + fun onSelectedItemsListener(listener: OnSelectedItemsListener) = apply { + this@ListSelectionView.onSelectedItemsChanged = listener } fun withSelectionType(type: SelectionType) = apply { diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/BaseSelectionViewHolder.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/BaseSelectionViewHolder.kt new file mode 100644 index 0000000..a4b9af0 --- /dev/null +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/BaseSelectionViewHolder.kt @@ -0,0 +1,11 @@ +package ru.touchin.roboswag.base_filters.select_list_item.adapter + +import android.view.View +import androidx.recyclerview.widget.RecyclerView +import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem + +abstract class BaseSelectionViewHolder(val view: View) + : RecyclerView.ViewHolder(view) { + + abstract fun bind(item: ItemType) +} diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt index 93fadef..c88d331 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt @@ -2,25 +2,29 @@ package ru.touchin.roboswag.base_filters.select_list_item.adapter import androidx.recyclerview.widget.DiffUtil import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView -import ru.touchin.roboswag.base_filters.select_list_item.OnItemSelectedListener -import ru.touchin.roboswag.base_filters.select_list_item.model.RowSelectionItem +import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem import ru.touchin.roboswag.recyclerview_adapters.adapters.DelegationListAdapter -class SheetSelectionAdapter( - onItemSelectAction: OnItemSelectedListener, - selectionType: ListSelectionView.SelectionType -): DelegationListAdapter(object : DiffUtil.ItemCallback() { +class SheetSelectionAdapter( + onItemSelectAction: (ItemType) -> Unit, + selectionType: ListSelectionView.SelectionType, + factory: HolderFactoryType +): DelegationListAdapter(object : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: RowSelectionItem, newItem: RowSelectionItem): Boolean = - oldItem.id == newItem.id + override fun areItemsTheSame(oldItem: BaseSelectionItem, newItem: BaseSelectionItem): Boolean = + oldItem.isItemTheSame(newItem) - override fun areContentsTheSame(oldItem: RowSelectionItem, newItem: RowSelectionItem): Boolean = - oldItem == newItem + override fun areContentsTheSame(oldItem: BaseSelectionItem, newItem: BaseSelectionItem): Boolean = + oldItem.isContentTheSame(newItem) }) { init { - addDelegate(SheetSelectionDelegate(onItemSelectAction, selectionType)) + addDelegate(SheetSelectionDelegate( + onItemSelectAction = onItemSelectAction, + selectionType = selectionType, + factory = factory + )) } } diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt index 31982ba..15540a5 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt @@ -1,53 +1,56 @@ package ru.touchin.roboswag.base_filters.select_list_item.adapter -import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.recyclerview.widget.RecyclerView import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding -import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView.SelectionType -import ru.touchin.roboswag.base_filters.select_list_item.OnItemSelectedListener -import ru.touchin.roboswag.base_filters.select_list_item.model.RowSelectionItem +import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem import ru.touchin.roboswag.recyclerview_adapters.adapters.ItemAdapterDelegate -class SheetSelectionDelegate( - private val onItemSelectAction: OnItemSelectedListener, - private val selectionType: ListSelectionView.SelectionType -) : ItemAdapterDelegate() { +typealias HolderFactoryType = (ViewGroup, (ItemType) -> Unit, SelectionType) -> BaseSelectionViewHolder - override fun onCreateViewHolder(parent: ViewGroup): SelectionItemViewHolder = SelectionItemViewHolder( - binding = SelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false) - ) +class SheetSelectionDelegate( + private val onItemSelectAction: (ItemType) -> Unit, + private val selectionType: SelectionType, + private val factory: HolderFactoryType +) : ItemAdapterDelegate, ItemType>() + where ItemType : BaseSelectionItem { + + override fun onCreateViewHolder(parent: ViewGroup): BaseSelectionViewHolder = + factory.invoke(parent, onItemSelectAction, selectionType) override fun onBindViewHolder( - holder: SelectionItemViewHolder, - item: RowSelectionItem, + holder: BaseSelectionViewHolder, + item: ItemType, adapterPosition: Int, collectionPosition: Int, payloads: MutableList ) = holder.bind(item) - inner class SelectionItemViewHolder(val binding: SelectionItemBinding) : RecyclerView.ViewHolder(binding.root) { +} - fun bind(item: RowSelectionItem) { - binding.run { - val checkListener = View.OnClickListener { - itemRadiobutton.isChecked = true - onItemSelectAction.invoke(item.copy(isSelected = when (selectionType) { - SelectionType.SINGLE_SELECT -> true - else -> !item.isSelected - })) - } +class SelectionItemViewHolder(private val binding: SelectionItemBinding, + private val onItemSelectAction: (ItemType) -> Unit, + private val selectionType: SelectionType + ) : BaseSelectionViewHolder(binding.root) { - itemTitle.text = item.title - root.setOnClickListener(checkListener) - - itemRadiobutton.setOnClickListener(checkListener) - itemRadiobutton.isChecked = item.isSelected + override fun bind(item: ItemType) { + binding.run { + val checkListener = View.OnClickListener { + itemRadiobutton.isChecked = true + onItemSelectAction.invoke(item.copyWithSelection(isSelected = when (selectionType) { + SelectionType.SINGLE_SELECT -> true + else -> !item.isSelected + })) } - } + itemTitle.text = item.title + root.setOnClickListener(checkListener) + + itemRadiobutton.setOnClickListener(checkListener) + itemRadiobutton.isChecked = item.isSelected + } } } + diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/BaseSelectionItem.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/BaseSelectionItem.kt new file mode 100644 index 0000000..b19d0d0 --- /dev/null +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/BaseSelectionItem.kt @@ -0,0 +1,14 @@ +package ru.touchin.roboswag.base_filters.select_list_item.model + +abstract class BaseSelectionItem( + open val id: Int, + open val title: String, + open val isSelected: Boolean +) { + + abstract fun isItemTheSame(compareItem: BaseSelectionItem): Boolean + + abstract fun isContentTheSame(compareItem: BaseSelectionItem): Boolean + + abstract fun copyWithSelection(isSelected: Boolean): ItemType +} diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/DefaultSelectionItem.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/DefaultSelectionItem.kt new file mode 100644 index 0000000..603961f --- /dev/null +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/DefaultSelectionItem.kt @@ -0,0 +1,24 @@ +package ru.touchin.roboswag.base_filters.select_list_item.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class DefaultSelectionItem( + override val id: Int, + override val title: String, + override val isSelected: Boolean = false +) : BaseSelectionItem(id, title, isSelected), Parcelable { + + override fun isItemTheSame(compareItem: BaseSelectionItem): Boolean = when { + compareItem is DefaultSelectionItem && id == compareItem.id -> true + else -> false + } + + override fun isContentTheSame(compareItem: BaseSelectionItem): Boolean = + this == compareItem + + @Suppress("UNCHECKED_CAST") + override fun copyWithSelection(isSelected: Boolean): ItemType = + this.copy(isSelected = isSelected) as ItemType +} diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/RowSelectionItem.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/RowSelectionItem.kt deleted file mode 100644 index 007eb69..0000000 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/RowSelectionItem.kt +++ /dev/null @@ -1,11 +0,0 @@ -package ru.touchin.roboswag.base_filters.select_list_item.model - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class RowSelectionItem( - val id: Int, - val title: String, - val isSelected: Boolean = false -): Parcelable From d8dc470805e5302499ec29d2d0fd7f35e84bc831 Mon Sep 17 00:00:00 2001 From: AnastasiyaK97 Date: Mon, 1 Aug 2022 12:42:00 +0300 Subject: [PATCH 5/8] =?UTF-8?q?SelectionItemViewHolder=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=20=D0=B2=20=D0=BE=D1=82=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D1=84=D0=B0=D0=B9=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/SelectionItemViewHolder.kt | 31 +++++++++++++++++++ .../adapter/SheetSelectionDelegate.kt | 28 ----------------- 2 files changed, 31 insertions(+), 28 deletions(-) create mode 100644 base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SelectionItemViewHolder.kt diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SelectionItemViewHolder.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SelectionItemViewHolder.kt new file mode 100644 index 0000000..cc81c0c --- /dev/null +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SelectionItemViewHolder.kt @@ -0,0 +1,31 @@ +package ru.touchin.roboswag.base_filters.select_list_item.adapter + +import android.view.View +import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding +import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView +import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem + +class SelectionItemViewHolder(private val binding: SelectionItemBinding, + private val onItemSelectAction: (ItemType) -> Unit, + private val selectionType: ListSelectionView.SelectionType + ) : BaseSelectionViewHolder(binding.root) { + + override fun bind(item: ItemType) { + binding.run { + val checkListener = View.OnClickListener { + itemRadiobutton.isChecked = true + onItemSelectAction.invoke(item.copyWithSelection(isSelected = when (selectionType) { + ListSelectionView.SelectionType.SINGLE_SELECT -> true + else -> !item.isSelected + })) + } + + itemTitle.text = item.title + root.setOnClickListener(checkListener) + + itemRadiobutton.setOnClickListener(checkListener) + itemRadiobutton.isChecked = item.isSelected + } + } + +} diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt index 15540a5..14f5460 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionDelegate.kt @@ -1,8 +1,6 @@ package ru.touchin.roboswag.base_filters.select_list_item.adapter -import android.view.View import android.view.ViewGroup -import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView.SelectionType import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem import ru.touchin.roboswag.recyclerview_adapters.adapters.ItemAdapterDelegate @@ -28,29 +26,3 @@ class SheetSelectionDelegate( ) = holder.bind(item) } - -class SelectionItemViewHolder(private val binding: SelectionItemBinding, - private val onItemSelectAction: (ItemType) -> Unit, - private val selectionType: SelectionType - ) : BaseSelectionViewHolder(binding.root) { - - override fun bind(item: ItemType) { - binding.run { - val checkListener = View.OnClickListener { - itemRadiobutton.isChecked = true - onItemSelectAction.invoke(item.copyWithSelection(isSelected = when (selectionType) { - SelectionType.SINGLE_SELECT -> true - else -> !item.isSelected - })) - } - - itemTitle.text = item.title - root.setOnClickListener(checkListener) - - itemRadiobutton.setOnClickListener(checkListener) - itemRadiobutton.isChecked = item.isSelected - } - } - -} - From bf55cc957970e17f9874f4bd5f0c76e3c3c895ef Mon Sep 17 00:00:00 2001 From: AnastasiyaK97 Date: Mon, 29 Aug 2022 19:29:18 +0300 Subject: [PATCH 6/8] PR issues --- base-filters/README.md | 46 +++++++------- base-filters/build.gradle | 6 +- .../select_list_item/ListSelectionView.kt | 63 ++++++++++--------- .../adapter/BaseSelectionViewHolder.kt | 2 +- .../adapter/SelectionItemViewHolder.kt | 34 +++++----- .../adapter/SheetSelectionAdapter.kt | 4 +- .../model/BaseSelectionItem.kt | 2 +- base-filters/src/main/res/values/styles.xml | 5 +- 8 files changed, 86 insertions(+), 76 deletions(-) diff --git a/base-filters/README.md b/base-filters/README.md index 09d83de..27c7be0 100644 --- a/base-filters/README.md +++ b/base-filters/README.md @@ -13,16 +13,18 @@ ### Как использовать ``` kotlin val selectorView = ListSelectionView>(context) - .setItems(navArgs.items) - .addItemDecoration((TopDividerItemDecoration( - context = requireContext(), - drawableId = R.drawable.list_divider_1dp, - startMargin = START_MARGIN_DIVIDER_DP.px - ))) - .withSelectionType(ListSelectionView.SelectionType.SINGLE_SELECT) - .onResultListener { items -> - viewModel.dispatchAction(SelectItemAction.SelectItem(items)) } - .build() + .Builder() + .setItems(navArgs.items) + .addItemDecoration((TopDividerItemDecoration( + context = requireContext(), + drawableId = R.drawable.list_divider_1dp, + startMargin = START_MARGIN_DIVIDER_DP.px + ))) + .withSelectionType(ListSelectionView.SelectionType.SINGLE_SELECT) + .onResultListener { items -> + viewModel.dispatchAction(SelectItemAction.SelectItem(items)) + } + .build() ``` ### Конфигурации * при создании `ListSelectionView` необходимо передлать `ItemType` - класс модели данных в списке, `HolderType` - класс viewHolder-а в recyclerView. @@ -35,15 +37,16 @@ val selectorView = ListSelectionView)` используется для определения кастомного viewHolder для списка с недефолтной разметкой. ``` kotlin val selectorView = ListSelectionView(context) - .showInHolder { parent, clickListener, selectionType -> - TestItemViewHolder( - binding = TestSelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false), - onItemSelectAction = clickListener, - selectionType = selectionType - ) - } - ... - .build() + .Builder() + .showInHolder { parent, clickListener, selectionType -> + TestItemViewHolder( + binding = TestSelectionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false), + onItemSelectAction = clickListener, + selectionType = selectionType + ) + } + ... + .build() ``` * колбэк `onSelectedItemsListener(listener: OnSelectedItemsListener)` можно использовать для получения списка всех элементов `ItemType` после каждого выбора * колбэк `onSelectedItemListener(listener: OnSelectedItemListener)` можно использовать для получения элемента списка `ItemType`, по которому произошел клик @@ -80,6 +83,7 @@ val selectorView = ListSelectionView(cont ``` kotlin val newContext = ContextThemeWrapper(requireContext(), R.style.Theme_Custom_FilterSelection) val selectorView = ListSelectionView(newContext) - ... - .build() + .Builder() + ... + .build() ``` diff --git a/base-filters/build.gradle b/base-filters/build.gradle index a8904a1..6c57558 100644 --- a/base-filters/build.gradle +++ b/base-filters/build.gradle @@ -19,7 +19,11 @@ dependencies { implementation("androidx.appcompat:appcompat") implementation("com.google.android.material:material") - implementation("androidx.constraintlayout:constraintlayout:2.2.0-alpha03") + implementation("androidx.constraintlayout:constraintlayout") { + version { + require '2.0.0' + } + } constraints { implementation("androidx.appcompat:appcompat") { diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt index e095ada..b47bcbc 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/ListSelectionView.kt @@ -13,8 +13,8 @@ import ru.touchin.roboswag.base_filters.select_list_item.adapter.SelectionItemVi import ru.touchin.roboswag.base_filters.select_list_item.adapter.SheetSelectionAdapter import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem -typealias OnSelectedItemListener = (item: ItemType) -> Unit -typealias OnSelectedItemsListener = (items: List) -> Unit +private typealias OnSelectedItemListener = (item: ItemType) -> Unit +private typealias OnSelectedItemsListener = (items: List) -> Unit /** * Base [ListSelectionView] to use in filters screen for choosing single or multi items in list. @@ -25,7 +25,7 @@ typealias OnSelectedItemsListener = (items: List) -> Unit * @param HolderType Type of viewHolder in recyclerView. * It must implement [BaseSelectionViewHolder] abstract class. * -**/ + **/ class ListSelectionView @JvmOverloads constructor( context: Context, @@ -33,8 +33,8 @@ class ListSelectionView @JvmOverloads constructor( defStyleAttr: Int = 0, defStyleRes: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) - where ItemType: BaseSelectionItem, - HolderType: BaseSelectionViewHolder{ + where ItemType : BaseSelectionItem, + HolderType : BaseSelectionViewHolder { private var mutableItems: List = emptyList() private var selectionType = SelectionType.SINGLE_SELECT @@ -82,38 +82,41 @@ class ListSelectionView @JvmOverloads constructor( updateList() } - fun setItems(items: List) = apply { - mutableItems = items - } + inner class Builder { - fun setItems( - source: List, - mapper: (T) -> ItemType - ) = setItems(source.map { item -> mapper.invoke(item) }) + fun setItems(items: List) = apply { + mutableItems = items + } - fun showInHolder(holderFactory: HolderFactoryType) = apply { - factory = holderFactory - } + fun setItems( + source: List, + mapper: (T) -> ItemType + ) = setItems(source.map { item -> mapper.invoke(item) }) - fun addItemDecoration(itemDecoration: RecyclerView.ItemDecoration) = apply { - binding.itemsRecycler.addItemDecoration(itemDecoration) - } + fun showInHolder(holderFactory: HolderFactoryType) = apply { + factory = holderFactory + } - fun onSelectedItemListener(listener: OnSelectedItemListener) = apply { - this@ListSelectionView.onSelectedItemChanged = listener - } + fun addItemDecoration(itemDecoration: RecyclerView.ItemDecoration) = apply { + binding.itemsRecycler.addItemDecoration(itemDecoration) + } - fun onSelectedItemsListener(listener: OnSelectedItemsListener) = apply { - this@ListSelectionView.onSelectedItemsChanged = listener - } + fun onSelectedItemListener(listener: OnSelectedItemListener) = apply { + this@ListSelectionView.onSelectedItemChanged = listener + } - fun withSelectionType(type: SelectionType) = apply { - selectionType = type - } + fun onSelectedItemsListener(listener: OnSelectedItemsListener) = apply { + this@ListSelectionView.onSelectedItemsChanged = listener + } - fun build() = apply { - binding.itemsRecycler.adapter = adapter - updateList() + fun withSelectionType(type: SelectionType) = apply { + selectionType = type + } + + fun build() = this@ListSelectionView.also { + binding.itemsRecycler.adapter = adapter + updateList() + } } enum class SelectionType { SINGLE_SELECT, MULTI_SELECT } diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/BaseSelectionViewHolder.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/BaseSelectionViewHolder.kt index a4b9af0..847bfc2 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/BaseSelectionViewHolder.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/BaseSelectionViewHolder.kt @@ -4,7 +4,7 @@ import android.view.View import androidx.recyclerview.widget.RecyclerView import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem -abstract class BaseSelectionViewHolder(val view: View) +abstract class BaseSelectionViewHolder(val view: View) : RecyclerView.ViewHolder(view) { abstract fun bind(item: ItemType) diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SelectionItemViewHolder.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SelectionItemViewHolder.kt index cc81c0c..0fc9a88 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SelectionItemViewHolder.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SelectionItemViewHolder.kt @@ -5,27 +5,29 @@ import ru.touchin.roboswag.base_filters.databinding.SelectionItemBinding import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem -class SelectionItemViewHolder(private val binding: SelectionItemBinding, - private val onItemSelectAction: (ItemType) -> Unit, - private val selectionType: ListSelectionView.SelectionType - ) : BaseSelectionViewHolder(binding.root) { +class SelectionItemViewHolder( + private val binding: SelectionItemBinding, + private val onItemSelectAction: (ItemType) -> Unit, + private val selectionType: ListSelectionView.SelectionType +) : BaseSelectionViewHolder(binding.root) { override fun bind(item: ItemType) { - binding.run { - val checkListener = View.OnClickListener { - itemRadiobutton.isChecked = true - onItemSelectAction.invoke(item.copyWithSelection(isSelected = when (selectionType) { - ListSelectionView.SelectionType.SINGLE_SELECT -> true - else -> !item.isSelected - })) - } + binding.itemTitle.text = item.title + binding.itemRadiobutton.isChecked = item.isSelected - itemTitle.text = item.title - root.setOnClickListener(checkListener) + setupCheckListener(item) + } - itemRadiobutton.setOnClickListener(checkListener) - itemRadiobutton.isChecked = item.isSelected + private fun setupCheckListener(item: ItemType) = with(binding) { + val checkListener = View.OnClickListener { + itemRadiobutton.isChecked = true + onItemSelectAction.invoke(item.copyWithSelection(isSelected = when (selectionType) { + ListSelectionView.SelectionType.SINGLE_SELECT -> true + else -> !item.isSelected + })) } + root.setOnClickListener(checkListener) + itemRadiobutton.setOnClickListener(checkListener) } } diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt index c88d331..b8d6449 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/adapter/SheetSelectionAdapter.kt @@ -5,11 +5,11 @@ import ru.touchin.roboswag.base_filters.select_list_item.ListSelectionView import ru.touchin.roboswag.base_filters.select_list_item.model.BaseSelectionItem import ru.touchin.roboswag.recyclerview_adapters.adapters.DelegationListAdapter -class SheetSelectionAdapter( +class SheetSelectionAdapter( onItemSelectAction: (ItemType) -> Unit, selectionType: ListSelectionView.SelectionType, factory: HolderFactoryType -): DelegationListAdapter(object : DiffUtil.ItemCallback() { +) : DelegationListAdapter(object : DiffUtil.ItemCallback() { override fun areItemsTheSame(oldItem: BaseSelectionItem, newItem: BaseSelectionItem): Boolean = oldItem.isItemTheSame(newItem) diff --git a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/BaseSelectionItem.kt b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/BaseSelectionItem.kt index b19d0d0..8f59990 100644 --- a/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/BaseSelectionItem.kt +++ b/base-filters/src/main/java/ru/touchin/roboswag/base_filters/select_list_item/model/BaseSelectionItem.kt @@ -10,5 +10,5 @@ abstract class BaseSelectionItem( abstract fun isContentTheSame(compareItem: BaseSelectionItem): Boolean - abstract fun copyWithSelection(isSelected: Boolean): ItemType + abstract fun copyWithSelection(isSelected: Boolean): ItemType } diff --git a/base-filters/src/main/res/values/styles.xml b/base-filters/src/main/res/values/styles.xml index 3520002..380b4da 100644 --- a/base-filters/src/main/res/values/styles.xml +++ b/base-filters/src/main/res/values/styles.xml @@ -7,10 +7,7 @@