New filter implementation
parent
6c07abec56
commit
1908ce3e46
@ -1,48 +0,0 @@
|
||||
package org.koitharu.kotatsu.filter.ui
|
||||
|
||||
import android.content.Context
|
||||
import androidx.recyclerview.widget.AsyncListDiffer.ListListener
|
||||
import org.koitharu.kotatsu.core.model.titleResId
|
||||
import org.koitharu.kotatsu.core.ui.BaseListAdapter
|
||||
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
|
||||
import org.koitharu.kotatsu.core.ui.model.titleRes
|
||||
import org.koitharu.kotatsu.filter.ui.model.FilterItem
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
||||
import org.koitharu.kotatsu.list.ui.adapter.listHeaderAD
|
||||
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
|
||||
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
class FilterAdapter(
|
||||
listener: OnFilterChangedListener,
|
||||
listListener: ListListener<ListModel>,
|
||||
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {
|
||||
|
||||
init {
|
||||
addDelegate(ListItemType.FILTER_SORT, filterSortDelegate(listener))
|
||||
addDelegate(ListItemType.FILTER_TAG, filterTagDelegate(listener))
|
||||
addDelegate(ListItemType.FILTER_TAG_MULTI, filterTagMultipleDelegate(listener))
|
||||
addDelegate(ListItemType.FILTER_STATE, filterStateDelegate(listener))
|
||||
addDelegate(ListItemType.FILTER_LANGUAGE, filterLanguageDelegate(listener))
|
||||
addDelegate(ListItemType.HEADER, listHeaderAD(listener))
|
||||
addDelegate(ListItemType.STATE_LOADING, loadingStateAD())
|
||||
addDelegate(ListItemType.FOOTER_LOADING, loadingFooterAD())
|
||||
addDelegate(ListItemType.FOOTER_ERROR, filterErrorDelegate())
|
||||
differ.addListListener(listListener)
|
||||
}
|
||||
|
||||
override fun getSectionText(context: Context, position: Int): CharSequence? {
|
||||
val list = items
|
||||
for (i in (0..position).reversed()) {
|
||||
val item = list.getOrNull(i) as? FilterItem ?: continue
|
||||
when (item) {
|
||||
is FilterItem.Error -> null
|
||||
is FilterItem.Language -> item.getTitle(context.resources)
|
||||
is FilterItem.Sort -> context.getString(item.order.titleRes)
|
||||
is FilterItem.State -> context.getString(item.state.titleResId)
|
||||
is FilterItem.Tag -> item.tag.title
|
||||
}?.firstOrNull()?.uppercase()
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@ -1,103 +0,0 @@
|
||||
package org.koitharu.kotatsu.filter.ui
|
||||
|
||||
import android.widget.TextView
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.titleResId
|
||||
import org.koitharu.kotatsu.core.ui.model.titleRes
|
||||
import org.koitharu.kotatsu.core.util.ext.setChecked
|
||||
import org.koitharu.kotatsu.databinding.ItemCheckableMultipleBinding
|
||||
import org.koitharu.kotatsu.databinding.ItemCheckableSingleBinding
|
||||
import org.koitharu.kotatsu.filter.ui.model.FilterItem
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
fun filterSortDelegate(
|
||||
listener: OnFilterChangedListener,
|
||||
) = adapterDelegateViewBinding<FilterItem.Sort, ListModel, ItemCheckableSingleBinding>(
|
||||
{ layoutInflater, parent -> ItemCheckableSingleBinding.inflate(layoutInflater, parent, false) },
|
||||
) {
|
||||
|
||||
itemView.setOnClickListener {
|
||||
listener.setSortOrder(item.order)
|
||||
}
|
||||
|
||||
bind { payloads ->
|
||||
binding.root.setText(item.order.titleRes)
|
||||
binding.root.setChecked(item.isSelected, payloads.isNotEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
fun filterStateDelegate(
|
||||
listener: OnFilterChangedListener,
|
||||
) = adapterDelegateViewBinding<FilterItem.State, ListModel, ItemCheckableMultipleBinding>(
|
||||
{ layoutInflater, parent -> ItemCheckableMultipleBinding.inflate(layoutInflater, parent, false) },
|
||||
) {
|
||||
|
||||
itemView.setOnClickListener {
|
||||
listener.setState(item.state, !item.isChecked)
|
||||
}
|
||||
|
||||
bind { payloads ->
|
||||
binding.root.setText(item.state.titleResId)
|
||||
binding.root.setChecked(item.isChecked, payloads.isNotEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun filterLanguageDelegate(
|
||||
listener: OnFilterChangedListener,
|
||||
) = adapterDelegateViewBinding<FilterItem.Language, ListModel, ItemCheckableSingleBinding>(
|
||||
{ layoutInflater, parent -> ItemCheckableSingleBinding.inflate(layoutInflater, parent, false) },
|
||||
) {
|
||||
|
||||
itemView.setOnClickListener {
|
||||
listener.setLanguage(item.locale)
|
||||
}
|
||||
|
||||
bind { payloads ->
|
||||
binding.root.text = item.getTitle(context.resources)
|
||||
binding.root.setChecked(item.isChecked, payloads.isNotEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
fun filterTagDelegate(
|
||||
listener: OnFilterChangedListener,
|
||||
) = adapterDelegateViewBinding<FilterItem.Tag, ListModel, ItemCheckableSingleBinding>(
|
||||
{ layoutInflater, parent -> ItemCheckableSingleBinding.inflate(layoutInflater, parent, false) },
|
||||
on = { item, _, _ -> item is FilterItem.Tag && !item.isMultiple },
|
||||
) {
|
||||
|
||||
itemView.setOnClickListener {
|
||||
listener.setTag(item.tag, !item.isChecked)
|
||||
}
|
||||
|
||||
bind { payloads ->
|
||||
binding.root.text = item.tag.title
|
||||
binding.root.setChecked(item.isChecked, payloads.isNotEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
fun filterTagMultipleDelegate(
|
||||
listener: OnFilterChangedListener,
|
||||
) = adapterDelegateViewBinding<FilterItem.Tag, ListModel, ItemCheckableMultipleBinding>(
|
||||
{ layoutInflater, parent -> ItemCheckableMultipleBinding.inflate(layoutInflater, parent, false) },
|
||||
on = { item, _, _ -> item is FilterItem.Tag && item.isMultiple },
|
||||
) {
|
||||
|
||||
itemView.setOnClickListener {
|
||||
listener.setTag(item.tag, !item.isChecked)
|
||||
}
|
||||
|
||||
bind { payloads ->
|
||||
binding.root.text = item.tag.title
|
||||
binding.root.setChecked(item.isChecked, payloads.isNotEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
fun filterErrorDelegate() = adapterDelegate<FilterItem.Error, ListModel>(R.layout.item_sources_empty) {
|
||||
|
||||
bind {
|
||||
(itemView as TextView).setText(item.textResId)
|
||||
}
|
||||
}
|
||||
@ -1,101 +0,0 @@
|
||||
package org.koitharu.kotatsu.filter.ui.model
|
||||
|
||||
import android.content.res.Resources
|
||||
import androidx.annotation.StringRes
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||
import java.util.Locale
|
||||
|
||||
sealed interface FilterItem : ListModel {
|
||||
|
||||
data class Sort(
|
||||
val order: SortOrder,
|
||||
val isSelected: Boolean,
|
||||
) : FilterItem {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is Sort && other.order == order
|
||||
}
|
||||
|
||||
override fun getChangePayload(previousState: ListModel): Any? {
|
||||
return if (previousState is Sort && previousState.isSelected != isSelected) {
|
||||
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
|
||||
} else {
|
||||
super.getChangePayload(previousState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Tag(
|
||||
val tag: MangaTag,
|
||||
val isMultiple: Boolean,
|
||||
val isChecked: Boolean,
|
||||
) : FilterItem {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is Tag && other.isMultiple == isMultiple && other.tag == tag
|
||||
}
|
||||
|
||||
override fun getChangePayload(previousState: ListModel): Any? {
|
||||
return if (previousState is Tag && previousState.isChecked != isChecked) {
|
||||
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
|
||||
} else {
|
||||
super.getChangePayload(previousState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class State(
|
||||
val state: MangaState,
|
||||
val isChecked: Boolean
|
||||
) : FilterItem {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is State && other.state == state
|
||||
}
|
||||
|
||||
override fun getChangePayload(previousState: ListModel): Any? {
|
||||
return if (previousState is State && previousState.isChecked != isChecked) {
|
||||
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
|
||||
} else {
|
||||
super.getChangePayload(previousState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Language(
|
||||
val locale: Locale?,
|
||||
val isChecked: Boolean,
|
||||
) : FilterItem {
|
||||
|
||||
private val displayText = locale?.getDisplayLanguage(locale)?.toTitleCase(locale)
|
||||
|
||||
fun getTitle(resources: Resources) = displayText ?: resources.getString(R.string.various_languages)
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is Language && other.locale == locale
|
||||
}
|
||||
|
||||
override fun getChangePayload(previousState: ListModel): Any? {
|
||||
return if (previousState is Language && previousState.isChecked != isChecked) {
|
||||
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
|
||||
} else {
|
||||
super.getChangePayload(previousState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class Error(
|
||||
@StringRes val textResId: Int,
|
||||
) : FilterItem {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is Error && textResId == other.textResId
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package org.koitharu.kotatsu.filter.ui.model
|
||||
|
||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||
|
||||
data class TagCatalogItem(
|
||||
val tag: MangaTag,
|
||||
val isChecked: Boolean,
|
||||
) : ListModel {
|
||||
|
||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
||||
return other is TagCatalogItem && other.tag == tag
|
||||
}
|
||||
|
||||
override fun getChangePayload(previousState: ListModel): Any? {
|
||||
return if (previousState is TagCatalogItem && previousState.isChecked != isChecked) {
|
||||
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
|
||||
} else {
|
||||
super.getChangePayload(previousState)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package org.koitharu.kotatsu.filter.ui.tags
|
||||
|
||||
import android.content.Context
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.core.ui.BaseListAdapter
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.list.fastscroll.FastScroller
|
||||
import org.koitharu.kotatsu.core.util.ext.setChecked
|
||||
import org.koitharu.kotatsu.databinding.ItemCheckableNewBinding
|
||||
import org.koitharu.kotatsu.filter.ui.model.TagCatalogItem
|
||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
||||
import org.koitharu.kotatsu.list.ui.adapter.ListItemType
|
||||
import org.koitharu.kotatsu.list.ui.adapter.errorFooterAD
|
||||
import org.koitharu.kotatsu.list.ui.adapter.loadingFooterAD
|
||||
import org.koitharu.kotatsu.list.ui.adapter.loadingStateAD
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
class TagsCatalogAdapter(
|
||||
listener: OnListItemClickListener<TagCatalogItem>,
|
||||
) : BaseListAdapter<ListModel>(), FastScroller.SectionIndexer {
|
||||
|
||||
init {
|
||||
addDelegate(ListItemType.FILTER_TAG, tagCatalogDelegate(listener))
|
||||
addDelegate(ListItemType.STATE_LOADING, loadingStateAD())
|
||||
addDelegate(ListItemType.FOOTER_LOADING, loadingFooterAD())
|
||||
addDelegate(ListItemType.FOOTER_ERROR, errorFooterAD(null))
|
||||
}
|
||||
|
||||
override fun getSectionText(context: Context, position: Int): CharSequence? {
|
||||
return (items.getOrNull(position) as? TagCatalogItem)?.tag?.title?.firstOrNull()?.uppercase()
|
||||
}
|
||||
|
||||
private fun tagCatalogDelegate(
|
||||
listener: OnListItemClickListener<TagCatalogItem>,
|
||||
) = adapterDelegateViewBinding<TagCatalogItem, ListModel, ItemCheckableNewBinding>(
|
||||
{ layoutInflater, parent -> ItemCheckableNewBinding.inflate(layoutInflater, parent, false) },
|
||||
) {
|
||||
|
||||
itemView.setOnClickListener {
|
||||
listener.onItemClick(item, itemView)
|
||||
}
|
||||
|
||||
bind { payloads ->
|
||||
binding.root.text = item.tag.title
|
||||
binding.root.setChecked(item.isChecked, ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED in payloads)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
package org.koitharu.kotatsu.filter.ui.tags
|
||||
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.viewModels
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import dagger.hilt.android.lifecycle.withCreationCallback
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetBehavior
|
||||
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetCallback
|
||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.showDistinct
|
||||
import org.koitharu.kotatsu.databinding.SheetTagsBinding
|
||||
import org.koitharu.kotatsu.filter.ui.FilterOwner
|
||||
import org.koitharu.kotatsu.filter.ui.model.TagCatalogItem
|
||||
|
||||
@AndroidEntryPoint
|
||||
class TagsCatalogSheet : BaseAdaptiveSheet<SheetTagsBinding>(), OnListItemClickListener<TagCatalogItem>, TextWatcher,
|
||||
AdaptiveSheetCallback, View.OnClickListener, View.OnFocusChangeListener, TextView.OnEditorActionListener {
|
||||
|
||||
private val viewModel by viewModels<TagsCatalogViewModel>(
|
||||
extrasProducer = {
|
||||
defaultViewModelCreationExtras.withCreationCallback<TagsCatalogViewModel.Factory> { factory ->
|
||||
factory.create((requireActivity() as FilterOwner).filter)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): SheetTagsBinding {
|
||||
return SheetTagsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewBindingCreated(binding: SheetTagsBinding, savedInstanceState: Bundle?) {
|
||||
super.onViewBindingCreated(binding, savedInstanceState)
|
||||
val adapter = TagsCatalogAdapter(this)
|
||||
binding.recyclerView.adapter = adapter
|
||||
binding.recyclerView.setHasFixedSize(true)
|
||||
binding.editSearch.setText(viewModel.searchQuery.value)
|
||||
binding.editSearch.addTextChangedListener(this)
|
||||
binding.editSearch.onFocusChangeListener = this
|
||||
binding.editSearch.setOnEditorActionListener(this)
|
||||
binding.buttonSearchClear.setOnClickListener(this)
|
||||
viewModel.content.observe(viewLifecycleOwner, adapter)
|
||||
addSheetCallback(this)
|
||||
disableFitToContents()
|
||||
}
|
||||
|
||||
override fun onItemClick(item: TagCatalogItem, view: View) {
|
||||
val filter = (requireActivity() as FilterOwner).filter
|
||||
filter.setTag(item.tag, true)
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.button_search_clear -> viewBinding?.editSearch?.text?.clear()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFocusChange(v: View?, hasFocus: Boolean) {
|
||||
setExpanded(
|
||||
isExpanded = hasFocus || isExpanded,
|
||||
isLocked = hasFocus,
|
||||
)
|
||||
}
|
||||
|
||||
override fun onEditorAction(v: TextView, actionId: Int, event: KeyEvent?): Boolean {
|
||||
return if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
v.clearFocus()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
val q = s?.toString().orEmpty()
|
||||
viewModel.searchQuery.value = q
|
||||
viewBinding?.buttonSearchClear?.isVisible = q.isNotEmpty()
|
||||
}
|
||||
|
||||
override fun onStateChanged(sheet: View, newState: Int) {
|
||||
viewBinding?.recyclerView?.isFastScrollerEnabled = newState == AdaptiveSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "TagsCatalogSheet"
|
||||
|
||||
fun show(fm: FragmentManager) = TagsCatalogSheet().showDistinct(fm, TAG)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package org.koitharu.kotatsu.filter.ui.tags
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.core.parser.MangaDataRepository
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.filter.ui.MangaFilter
|
||||
import org.koitharu.kotatsu.filter.ui.model.TagCatalogItem
|
||||
import org.koitharu.kotatsu.list.ui.model.LoadingState
|
||||
|
||||
@HiltViewModel(assistedFactory = TagsCatalogViewModel.Factory::class)
|
||||
class TagsCatalogViewModel @AssistedInject constructor(
|
||||
@Assisted filter: MangaFilter,
|
||||
mangaRepositoryFactory: MangaRepository.Factory,
|
||||
dataRepository: MangaDataRepository,
|
||||
) : BaseViewModel() {
|
||||
|
||||
val searchQuery = MutableStateFlow("")
|
||||
|
||||
private val tags = combine(
|
||||
filter.allTags,
|
||||
filter.filterTags.map { it.selectedItems },
|
||||
) { all, selected ->
|
||||
all.map { x ->
|
||||
if (x is TagCatalogItem) {
|
||||
val checked = x.tag in selected
|
||||
if (x.isChecked == checked) {
|
||||
x
|
||||
} else {
|
||||
x.copy(isChecked = checked)
|
||||
}
|
||||
} else {
|
||||
x
|
||||
}
|
||||
}
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, filter.allTags.value)
|
||||
|
||||
val content = combine(tags, searchQuery) { raw, query ->
|
||||
raw.filter { x ->
|
||||
x !is TagCatalogItem || x.tag.title.contains(query, ignoreCase = true)
|
||||
}
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Lazily, listOf(LoadingState))
|
||||
|
||||
@AssistedFactory
|
||||
interface Factory {
|
||||
fun create(filter: MangaFilter): TagsCatalogViewModel
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,12 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="?listPreferredItemPaddingStart"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingEnd="?listPreferredItemPaddingEnd"
|
||||
android:paddingBottom="6dp"
|
||||
app:chipSpacingHorizontal="6dp"
|
||||
app:chipSpacingVertical="6dp" />
|
||||
android:paddingBottom="6dp" />
|
||||
|
||||
@ -1,143 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||
android:id="@+id/headerBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:title="@string/filter" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scrollView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollIndicators="top">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="@dimen/margin_normal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_order_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||
android:singleLine="true"
|
||||
android:text="@string/sort_order"
|
||||
android:textAppearance="?textAppearanceTitleSmall"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_order"
|
||||
style="?materialCardViewOutlinedStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="@dimen/margin_normal"
|
||||
android:visibility="gone"
|
||||
app:cardBackgroundColor="?m3ColorBackground"
|
||||
app:shapeAppearance="?shapeAppearanceCornerMedium"
|
||||
app:strokeColor="@color/m3_button_outline_color_selector"
|
||||
app:strokeWidth="@dimen/m3_comp_outlined_button_outline_width"
|
||||
tools:visibility="visible">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_order"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?listPreferredItemHeightSmall" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_locale_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||
android:layout_marginTop="@dimen/margin_normal"
|
||||
android:singleLine="true"
|
||||
android:text="@string/language"
|
||||
android:textAppearance="?textAppearanceTitleSmall"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/card_locale"
|
||||
style="?materialCardViewOutlinedStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="@dimen/margin_normal"
|
||||
android:visibility="gone"
|
||||
app:cardBackgroundColor="?m3ColorBackground"
|
||||
app:shapeAppearance="?shapeAppearanceCornerMedium"
|
||||
app:strokeColor="@color/m3_button_outline_color_selector"
|
||||
app:strokeWidth="@dimen/m3_comp_outlined_button_outline_width"
|
||||
tools:visibility="visible">
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_locale"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="?listPreferredItemHeightSmall" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_genres_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||
android:layout_marginTop="@dimen/margin_normal"
|
||||
android:singleLine="true"
|
||||
android:text="@string/genres"
|
||||
android:textAppearance="?textAppearanceTitleSmall"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||
android:id="@+id/chips_genres"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/margin_normal"
|
||||
android:paddingHorizontal="@dimen/margin_normal"
|
||||
android:visibility="gone"
|
||||
app:chipSpacingHorizontal="6dp"
|
||||
app:chipSpacingVertical="6dp"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_state_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||
android:layout_marginTop="@dimen/margin_normal"
|
||||
android:singleLine="true"
|
||||
android:text="@string/state"
|
||||
android:textAppearance="?textAppearanceTitleSmall"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||
android:id="@+id/chips_state"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/margin_normal"
|
||||
android:paddingHorizontal="@dimen/margin_normal"
|
||||
android:visibility="gone"
|
||||
app:chipSpacingHorizontal="6dp"
|
||||
app:chipSpacingVertical="6dp"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</LinearLayout>
|
||||
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||
android:id="@+id/headerBar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:title="@string/filter" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/edit_search"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableStart="?android:actionModeWebSearchDrawable"
|
||||
android:drawablePadding="12dp"
|
||||
android:hint="@string/genres_search_hint"
|
||||
android:imeOptions="actionSearch|flagNoFullscreen"
|
||||
android:importantForAutofill="no"
|
||||
android:inputType="text"
|
||||
android:paddingHorizontal="6dp"
|
||||
android:singleLine="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/headerBar"
|
||||
tools:ignore="LabelFor" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/button_search_clear"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/clear"
|
||||
android:minWidth="?minTouchTargetSize"
|
||||
android:minHeight="?minTouchTargetSize"
|
||||
android:src="@drawable/abc_ic_clear_material"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/edit_search"
|
||||
app:layout_constraintEnd_toEndOf="@id/edit_search"
|
||||
app:layout_constraintTop_toTopOf="@id/edit_search"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.list.fastscroll.FastScrollRecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
app:bubbleSize="normal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/edit_search"
|
||||
app:scrollerOffset="8dp"
|
||||
tools:listitem="@layout/item_checkable_new" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Loading…
Reference in New Issue