mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-12 20:19:05 +01:00
Filters with flexible adapter
This commit is contained in:
@@ -237,10 +237,10 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
|
||||
}
|
||||
|
||||
navView.onSearchClicked = {
|
||||
val allDefault = navView.adapter.items.hasSameState(presenter.source.getFilterList())
|
||||
val allDefault = presenter.sourceFilters == presenter.source.getFilterList()
|
||||
showProgressBar()
|
||||
adapter.clear()
|
||||
presenter.setSourceFilter(if (allDefault) FilterList() else navView.adapter.items)
|
||||
presenter.setSourceFilter(if (allDefault) FilterList() else presenter.sourceFilters)
|
||||
}
|
||||
|
||||
navView.onResetClicked = {
|
||||
|
||||
@@ -1,29 +1,24 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue
|
||||
|
||||
import android.content.Context
|
||||
import android.support.graphics.drawable.VectorDrawableCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.davidea.flexibleadapter.items.ISectionable
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
import eu.kanade.tachiyomi.data.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.util.dpToPx
|
||||
import eu.kanade.tachiyomi.util.getResourceColor
|
||||
import eu.kanade.tachiyomi.ui.catalogue.filter.*
|
||||
import eu.kanade.tachiyomi.util.inflate
|
||||
import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
|
||||
import eu.kanade.tachiyomi.widget.SimpleNavigationView
|
||||
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
||||
import kotlinx.android.synthetic.main.catalogue_drawer_content.view.*
|
||||
|
||||
|
||||
class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
|
||||
: SimpleNavigationView(context, attrs) {
|
||||
|
||||
val adapter = Adapter()
|
||||
val adapter = FlexibleAdapter<IFlexible<*>>(null)
|
||||
|
||||
var onSearchClicked = {}
|
||||
|
||||
@@ -32,170 +27,52 @@ class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs:
|
||||
init {
|
||||
recycler.adapter = adapter
|
||||
val view = inflate(R.layout.catalogue_drawer_content)
|
||||
(view as ViewGroup).addView(recycler)
|
||||
((view as ViewGroup).getChildAt(1) as ViewGroup).addView(recycler)
|
||||
addView(view)
|
||||
|
||||
search_btn.setOnClickListener { onSearchClicked() }
|
||||
reset_btn.setOnClickListener { onResetClicked() }
|
||||
|
||||
adapter.setDisplayHeadersAtStartUp(true)
|
||||
adapter.setStickyHeaders(true)
|
||||
}
|
||||
|
||||
fun setFilters(items: FilterList) {
|
||||
adapter.items = items
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
inner class Adapter : RecyclerView.Adapter<Holder>() {
|
||||
|
||||
var items: FilterList = FilterList()
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return items.size
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return when (items[position]) {
|
||||
is Filter.Header -> VIEW_TYPE_HEADER
|
||||
is Filter.Separator -> VIEW_TYPE_SEPARATOR
|
||||
is Filter.CheckBox -> VIEW_TYPE_CHECKBOX
|
||||
is Filter.TriState -> VIEW_TYPE_MULTISTATE
|
||||
is Filter.List<*> -> VIEW_TYPE_LIST
|
||||
is Filter.Text -> VIEW_TYPE_TEXT
|
||||
is Filter.Sort<*> -> VIEW_TYPE_SORT
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
|
||||
return when (viewType) {
|
||||
VIEW_TYPE_HEADER -> HeaderHolder(parent)
|
||||
VIEW_TYPE_SEPARATOR -> SeparatorHolder(parent)
|
||||
VIEW_TYPE_CHECKBOX -> CheckboxHolder(parent, null)
|
||||
VIEW_TYPE_MULTISTATE -> MultiStateHolder(parent, null).apply {
|
||||
// Adjust view with checkbox
|
||||
text.setPadding(4.dpToPx, 0, 0, 0)
|
||||
text.compoundDrawablePadding = 20.dpToPx
|
||||
}
|
||||
VIEW_TYPE_LIST -> SpinnerHolder(parent)
|
||||
VIEW_TYPE_TEXT -> EditTextHolder(parent)
|
||||
VIEW_TYPE_SORT -> SortHolder(parent)
|
||||
else -> throw Exception("Unknown view type")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: Holder, position: Int) {
|
||||
val filter = items[position]
|
||||
when (filter) {
|
||||
is Filter.Header -> {
|
||||
val view = holder.itemView as TextView
|
||||
view.visibility = if (filter.name.isEmpty()) View.GONE else View.VISIBLE
|
||||
view.text = filter.name
|
||||
}
|
||||
is Filter.CheckBox -> {
|
||||
val view = (holder as CheckboxHolder).check
|
||||
view.text = filter.name
|
||||
view.isChecked = filter.state
|
||||
holder.itemView.setOnClickListener {
|
||||
view.toggle()
|
||||
filter.state = view.isChecked
|
||||
}
|
||||
}
|
||||
is Filter.TriState -> {
|
||||
val view = (holder as MultiStateHolder).text
|
||||
view.text = filter.name
|
||||
|
||||
fun getIcon() = VectorDrawableCompat.create(view.resources, when (filter.state) {
|
||||
Filter.TriState.STATE_IGNORE -> R.drawable.ic_check_box_outline_blank_24dp
|
||||
Filter.TriState.STATE_INCLUDE -> R.drawable.ic_check_box_24dp
|
||||
Filter.TriState.STATE_EXCLUDE -> R.drawable.ic_check_box_x_24dp
|
||||
else -> throw Exception("Unknown state")
|
||||
}, null)?.apply {
|
||||
val color = if (filter.state == Filter.TriState.STATE_INCLUDE)
|
||||
R.attr.colorAccent
|
||||
else
|
||||
android.R.attr.textColorSecondary
|
||||
|
||||
setTint(view.context.getResourceColor(color))
|
||||
}
|
||||
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
|
||||
holder.itemView.setOnClickListener {
|
||||
filter.state = (filter.state + 1) % 3
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
|
||||
}
|
||||
}
|
||||
is Filter.List<*> -> {
|
||||
holder as SpinnerHolder
|
||||
holder.text.text = filter.name + ": "
|
||||
|
||||
val spinner = holder.spinner
|
||||
spinner.prompt = filter.name
|
||||
spinner.adapter = ArrayAdapter<Any>(holder.itemView.context,
|
||||
android.R.layout.simple_spinner_item, filter.values).apply {
|
||||
setDropDownViewResource(R.layout.spinner_item)
|
||||
}
|
||||
spinner.onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
|
||||
filter.state = position
|
||||
}
|
||||
spinner.setSelection(filter.state)
|
||||
}
|
||||
is Filter.Text -> {
|
||||
holder as EditTextHolder
|
||||
holder.wrapper.visibility = if (filter.name.isEmpty()) View.GONE else View.VISIBLE
|
||||
holder.wrapper.hint = filter.name
|
||||
holder.edit.setText(filter.state)
|
||||
holder.edit.addTextChangedListener(object : SimpleTextWatcher() {
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
filter.state = s.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
is Filter.Sort<*> -> {
|
||||
val view = (holder as SortHolder).sortView
|
||||
view.removeAllViews()
|
||||
if (!filter.name.isEmpty()) {
|
||||
val header = HeaderHolder(view)
|
||||
(header.itemView as TextView).text = filter.name
|
||||
view.addView(header.itemView)
|
||||
}
|
||||
val holders = Array<MultiStateHolder>(filter.values.size, { MultiStateHolder(view, null) })
|
||||
for ((i, rb) in holders.withIndex()) {
|
||||
rb.text.text = filter.values[i].toString()
|
||||
|
||||
fun getIcon() = when (filter.state) {
|
||||
Filter.Sort.Selection(i, false) -> VectorDrawableCompat.create(view.resources, R.drawable.ic_keyboard_arrow_down_black_32dp, null)
|
||||
?.apply { setTint(view.context.getResourceColor(R.attr.colorAccent)) }
|
||||
Filter.Sort.Selection(i, true) -> VectorDrawableCompat.create(view.resources, R.drawable.ic_keyboard_arrow_up_black_32dp, null)
|
||||
?.apply { setTint(view.context.getResourceColor(R.attr.colorAccent)) }
|
||||
else -> ContextCompat.getDrawable(context, R.drawable.empty_drawable_32dp)
|
||||
}
|
||||
|
||||
rb.text.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
|
||||
rb.itemView.setOnClickListener {
|
||||
val pre = filter.state?.index ?: i
|
||||
if (pre != i) {
|
||||
holders[pre].text.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
|
||||
filter.state = Filter.Sort.Selection(i, false)
|
||||
} else {
|
||||
filter.state = Filter.Sort.Selection(i, filter.state?.ascending == false)
|
||||
}
|
||||
rb.text.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
|
||||
}
|
||||
|
||||
view.addView(rb.itemView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val VIEW_TYPE_SORT = 0
|
||||
|
||||
private class SortHolder(parent: ViewGroup, val sortView: SortView = SortView(parent)) : Holder(sortView) {
|
||||
class SortView(parent: ViewGroup) : LinearLayout(parent.context) {
|
||||
init {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
fun setFilters(filters: FilterList) {
|
||||
val items = filters.mapNotNull {
|
||||
when (it) {
|
||||
is Filter.Header -> HeaderItem(it)
|
||||
is Filter.Separator -> SeparatorItem(it)
|
||||
is Filter.CheckBox -> CheckboxItem(it)
|
||||
is Filter.TriState -> TriStateItem(it)
|
||||
is Filter.Text -> TextItem(it)
|
||||
is Filter.Select<*> -> SelectItem(it)
|
||||
is Filter.Group<*> -> {
|
||||
val group = GroupItem(it)
|
||||
val subItems = it.state.mapNotNull {
|
||||
when (it) {
|
||||
is Filter.CheckBox -> CheckboxSectionItem(it)
|
||||
is Filter.TriState -> TriStateSectionItem(it)
|
||||
is Filter.Text -> TextSectionItem(it)
|
||||
is Filter.Select<*> -> SelectSectionItem(it)
|
||||
else -> null
|
||||
} as? ISectionable<*, *>
|
||||
}
|
||||
subItems.forEach { it.header = group }
|
||||
group.subItems = subItems
|
||||
group
|
||||
}
|
||||
is Filter.Sort -> {
|
||||
val group = SortGroup(it)
|
||||
val subItems = it.values.mapNotNull {
|
||||
SortItem(it, group)
|
||||
}
|
||||
group.subItems = subItems
|
||||
group
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
adapter.updateDataSet(items)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CheckBox
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
|
||||
open class CheckboxItem(val filter: Filter.CheckBox) : AbstractFlexibleItem<CheckboxItem.Holder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.navigation_view_checkbox
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
val view = holder.check
|
||||
view.text = filter.name
|
||||
view.isChecked = filter.state
|
||||
holder.itemView.setOnClickListener {
|
||||
view.toggle()
|
||||
filter.state = view.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is CheckboxItem) {
|
||||
return filter == other.filter
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return filter.hashCode()
|
||||
}
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
||||
|
||||
val check = itemView.findViewById(R.id.nav_view_item) as CheckBox
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.ISectionable
|
||||
import eu.davidea.viewholders.ExpandableViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
import eu.kanade.tachiyomi.util.setVectorCompat
|
||||
|
||||
class GroupItem(val filter: Filter.Group<*>) : AbstractExpandableHeaderItem<GroupItem.Holder, ISectionable<*, *>>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.navigation_view_group
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
holder.title.text = filter.name
|
||||
|
||||
holder.icon.setVectorCompat(if (isExpanded)
|
||||
R.drawable.ic_expand_more_white_24dp
|
||||
else
|
||||
R.drawable.ic_chevron_right_white_24dp)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is GroupItem) {
|
||||
return filter == other.filter
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return filter.hashCode()
|
||||
}
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : ExpandableViewHolder(view, adapter, true) {
|
||||
|
||||
val title = itemView.findViewById(R.id.title) as TextView
|
||||
val icon = itemView.findViewById(R.id.expand_icon) as ImageView
|
||||
|
||||
override fun shouldNotifyParentOnClick(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.support.design.R
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
|
||||
class HeaderItem(val filter: Filter.Header) : AbstractHeaderItem<HeaderItem.Holder>() {
|
||||
|
||||
@SuppressLint("PrivateResource")
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.design_navigation_item_subheader
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
val view = holder.itemView as TextView
|
||||
view.visibility = if (filter.name.isEmpty()) View.GONE else View.VISIBLE
|
||||
view.text = filter.name
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is HeaderItem) {
|
||||
return filter == other.filter
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return filter.hashCode()
|
||||
}
|
||||
|
||||
class Holder(view: View, val adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import eu.davidea.flexibleadapter.items.ISectionable
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
|
||||
class TriStateSectionItem(filter: Filter.TriState) : TriStateItem(filter), ISectionable<TriStateItem.Holder, GroupItem> {
|
||||
|
||||
private var head: GroupItem? = null
|
||||
|
||||
override fun getHeader(): GroupItem? = head
|
||||
|
||||
override fun setHeader(header: GroupItem?) {
|
||||
head = header
|
||||
}
|
||||
}
|
||||
|
||||
class TextSectionItem(filter: Filter.Text) : TextItem(filter), ISectionable<TextItem.Holder, GroupItem> {
|
||||
|
||||
private var head: GroupItem? = null
|
||||
|
||||
override fun getHeader(): GroupItem? = head
|
||||
|
||||
override fun setHeader(header: GroupItem?) {
|
||||
head = header
|
||||
}
|
||||
}
|
||||
|
||||
class CheckboxSectionItem(filter: Filter.CheckBox) : CheckboxItem(filter), ISectionable<CheckboxItem.Holder, GroupItem> {
|
||||
|
||||
private var head: GroupItem? = null
|
||||
|
||||
override fun getHeader(): GroupItem? = head
|
||||
|
||||
override fun setHeader(header: GroupItem?) {
|
||||
head = header
|
||||
}
|
||||
}
|
||||
|
||||
class SelectSectionItem(filter: Filter.Select<*>) : SelectItem(filter), ISectionable<SelectItem.Holder, GroupItem> {
|
||||
|
||||
private var head: GroupItem? = null
|
||||
|
||||
override fun getHeader(): GroupItem? = head
|
||||
|
||||
override fun setHeader(header: GroupItem?) {
|
||||
head = header
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
|
||||
|
||||
open class SelectItem(val filter: Filter.Select<*>) : AbstractFlexibleItem<SelectItem.Holder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.navigation_view_spinner
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
holder.text.text = filter.name + ": "
|
||||
|
||||
val spinner = holder.spinner
|
||||
spinner.prompt = filter.name
|
||||
spinner.adapter = ArrayAdapter<Any>(holder.itemView.context,
|
||||
android.R.layout.simple_spinner_item, filter.values).apply {
|
||||
setDropDownViewResource(R.layout.spinner_item)
|
||||
}
|
||||
spinner.onItemSelectedListener = IgnoreFirstSpinnerListener { position ->
|
||||
filter.state = position
|
||||
}
|
||||
spinner.setSelection(filter.state)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is SelectItem) {
|
||||
return filter == other.filter
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return filter.hashCode()
|
||||
}
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
||||
|
||||
val text = itemView.findViewById(R.id.nav_view_item_text) as TextView
|
||||
val spinner = itemView.findViewById(R.id.nav_view_item) as Spinner
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.support.design.R
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractHeaderItem
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
|
||||
class SeparatorItem(val filter: Filter.Separator) : AbstractHeaderItem<SeparatorItem.Holder>() {
|
||||
|
||||
@SuppressLint("PrivateResource")
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.design_navigation_item_separator
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is SeparatorItem) {
|
||||
return filter == other.filter
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return filter.hashCode()
|
||||
}
|
||||
|
||||
class Holder(view: View, val adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter)
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem
|
||||
import eu.davidea.flexibleadapter.items.ISectionable
|
||||
import eu.davidea.viewholders.ExpandableViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
import eu.kanade.tachiyomi.util.setVectorCompat
|
||||
|
||||
class SortGroup(val filter: Filter.Sort) : AbstractExpandableHeaderItem<SortGroup.Holder, ISectionable<*, *>>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.navigation_view_sort
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
holder.title.text = filter.name
|
||||
|
||||
holder.icon.setVectorCompat(if (isExpanded)
|
||||
R.drawable.ic_expand_more_white_24dp
|
||||
else
|
||||
R.drawable.ic_chevron_right_white_24dp)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is SortGroup) {
|
||||
return filter == other.filter
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return filter.hashCode()
|
||||
}
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : ExpandableViewHolder(view, adapter, true) {
|
||||
|
||||
val title = itemView.findViewById(R.id.title) as TextView
|
||||
val icon = itemView.findViewById(R.id.expand_icon) as ImageView
|
||||
|
||||
override fun shouldNotifyParentOnClick(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import android.support.graphics.drawable.VectorDrawableCompat
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CheckedTextView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractSectionableItem
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
import eu.kanade.tachiyomi.util.getResourceColor
|
||||
|
||||
class SortItem(val name: String, val group: SortGroup) : AbstractSectionableItem<SortItem.Holder, SortGroup>(group) {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.navigation_view_sort_item
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
val view = holder.text
|
||||
view.text = name
|
||||
val filter = group.filter
|
||||
|
||||
val i = filter.values.indexOf(name)
|
||||
|
||||
fun getIcon() = when (filter.state) {
|
||||
Filter.Sort.Selection(i, false) -> VectorDrawableCompat.create(view.resources, R.drawable.ic_keyboard_arrow_down_black_32dp, null)
|
||||
?.apply { setTint(view.context.getResourceColor(R.attr.colorAccent)) }
|
||||
Filter.Sort.Selection(i, true) -> VectorDrawableCompat.create(view.resources, R.drawable.ic_keyboard_arrow_up_black_32dp, null)
|
||||
?.apply { setTint(view.context.getResourceColor(R.attr.colorAccent)) }
|
||||
else -> ContextCompat.getDrawable(view.context, R.drawable.empty_drawable_32dp)
|
||||
}
|
||||
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
|
||||
holder.itemView.setOnClickListener {
|
||||
val pre = filter.state?.index ?: i
|
||||
if (pre != i) {
|
||||
filter.state = Filter.Sort.Selection(i, false)
|
||||
} else {
|
||||
filter.state = Filter.Sort.Selection(i, filter.state?.ascending == false)
|
||||
}
|
||||
|
||||
group.subItems.forEach { adapter.notifyItemChanged(adapter.getGlobalPositionOf(it)) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is SortItem) {
|
||||
return name == other.name && group == other.group
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = name.hashCode()
|
||||
result = 31 * result + group.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
||||
|
||||
val text = itemView.findViewById(R.id.nav_view_item) as CheckedTextView
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import android.support.design.widget.TextInputLayout
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
||||
|
||||
open class TextItem(val filter: Filter.Text) : AbstractFlexibleItem<TextItem.Holder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.navigation_view_text
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
|
||||
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
holder.wrapper.visibility = if (filter.name.isEmpty()) View.GONE else View.VISIBLE
|
||||
holder.wrapper.hint = filter.name
|
||||
holder.edit.setText(filter.state)
|
||||
holder.edit.addTextChangedListener(object : SimpleTextWatcher() {
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
filter.state = s.toString()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is TextItem) {
|
||||
return filter == other.filter
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return filter.hashCode()
|
||||
}
|
||||
|
||||
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
||||
|
||||
val wrapper = itemView.findViewById(R.id.nav_view_item_wrapper) as TextInputLayout
|
||||
val edit = itemView.findViewById(R.id.nav_view_item) as EditText
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package eu.kanade.tachiyomi.ui.catalogue.filter
|
||||
|
||||
import android.support.design.R
|
||||
import android.support.graphics.drawable.VectorDrawableCompat
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CheckedTextView
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||
import eu.davidea.viewholders.FlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.data.source.model.Filter
|
||||
import eu.kanade.tachiyomi.util.dpToPx
|
||||
import eu.kanade.tachiyomi.util.getResourceColor
|
||||
import eu.kanade.tachiyomi.R as TR
|
||||
|
||||
open class TriStateItem(val filter: Filter.TriState) : AbstractFlexibleItem<TriStateItem.Holder>() {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return TR.layout.navigation_view_checkedtext
|
||||
}
|
||||
|
||||
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup?): Holder {
|
||||
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
|
||||
}
|
||||
|
||||
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||
val view = holder.text
|
||||
view.text = filter.name
|
||||
|
||||
fun getIcon() = VectorDrawableCompat.create(view.resources, when (filter.state) {
|
||||
Filter.TriState.STATE_IGNORE -> TR.drawable.ic_check_box_outline_blank_24dp
|
||||
Filter.TriState.STATE_INCLUDE -> TR.drawable.ic_check_box_24dp
|
||||
Filter.TriState.STATE_EXCLUDE -> TR.drawable.ic_check_box_x_24dp
|
||||
else -> throw Exception("Unknown state")
|
||||
}, null)?.apply {
|
||||
val color = if (filter.state == Filter.TriState.STATE_INCLUDE)
|
||||
R.attr.colorAccent
|
||||
else
|
||||
android.R.attr.textColorSecondary
|
||||
|
||||
setTint(view.context.getResourceColor(color))
|
||||
}
|
||||
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
|
||||
holder.itemView.setOnClickListener {
|
||||
filter.state = (filter.state + 1) % 3
|
||||
view.setCompoundDrawablesWithIntrinsicBounds(getIcon(), null, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other is TriStateItem) {
|
||||
return filter == other.filter
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return filter.hashCode()
|
||||
}
|
||||
|
||||
class Holder(view: View, val adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
||||
|
||||
val text = itemView.findViewById(TR.id.nav_view_item) as CheckedTextView
|
||||
|
||||
init {
|
||||
// Align with native checkbox
|
||||
text.setPadding(4.dpToPx, 0, 0, 0)
|
||||
text.compoundDrawablePadding = 20.dpToPx
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,6 @@ class CategoryAdapter(private val activity: CategoryActivity) :
|
||||
* Called when item is released.
|
||||
*/
|
||||
fun onItemReleased() {
|
||||
// Update database
|
||||
activity.onItemReleased()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user