From 90a99dde1f18665d1b117601c43265247afb9fc3 Mon Sep 17 00:00:00 2001 From: len Date: Sat, 14 Jan 2017 22:38:31 +0100 Subject: [PATCH] Filters with flexible adapter --- .../tachiyomi/data/source/model/Filter.kt | 19 +- .../tachiyomi/data/source/model/FilterList.kt | 9 +- .../data/source/online/english/Batoto.kt | 10 +- .../data/source/online/english/Mangafox.kt | 24 +- .../data/source/online/english/Mangahere.kt | 10 +- .../data/source/online/english/Mangasee.kt | 16 +- .../source/online/english/Readmangatoday.kt | 2 +- .../ui/catalogue/CatalogueFragment.kt | 4 +- .../ui/catalogue/CatalogueNavigationView.kt | 209 ++++-------------- .../ui/catalogue/filter/CheckboxItem.kt | 49 ++++ .../ui/catalogue/filter/GroupItem.kt | 56 +++++ .../ui/catalogue/filter/HeaderItem.kt | 44 ++++ .../ui/catalogue/filter/SectionItems.kt | 48 ++++ .../ui/catalogue/filter/SelectItem.kt | 58 +++++ .../ui/catalogue/filter/SeparatorItem.kt | 41 ++++ .../ui/catalogue/filter/SortGroup.kt | 57 +++++ .../tachiyomi/ui/catalogue/filter/SortItem.kt | 73 ++++++ .../tachiyomi/ui/catalogue/filter/TextItem.kt | 53 +++++ .../ui/catalogue/filter/TriStateItem.kt | 75 +++++++ .../tachiyomi/ui/category/CategoryAdapter.kt | 1 - .../drawable/ic_chevron_right_white_24dp.xml | 9 + .../drawable/ic_expand_more_white_24dp.xml | 9 + .../res/layout/catalogue_drawer_content.xml | 4 + .../main/res/layout/navigation_view_group.xml | 30 +++ .../main/res/layout/navigation_view_sort.xml | 30 +++ .../res/layout/navigation_view_sort_item.xml | 21 ++ 26 files changed, 752 insertions(+), 209 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/CheckboxItem.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/HeaderItem.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SectionItems.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SelectItem.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SeparatorItem.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TextItem.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TriStateItem.kt create mode 100644 app/src/main/res/drawable/ic_chevron_right_white_24dp.xml create mode 100644 app/src/main/res/drawable/ic_expand_more_white_24dp.xml create mode 100644 app/src/main/res/layout/navigation_view_group.xml create mode 100644 app/src/main/res/layout/navigation_view_sort.xml create mode 100644 app/src/main/res/layout/navigation_view_sort_item.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/model/Filter.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/model/Filter.kt index c78074d98..7ea621466 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/model/Filter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/model/Filter.kt @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.data.source.model sealed class Filter(val name: String, var state: T) { open class Header(name: String) : Filter(name, 0) open class Separator(name: String = "") : Filter(name, 0) - abstract class List(name: String, val values: Array, state: Int = 0) : Filter(name, state) + abstract class Select(name: String, val values: Array, state: Int = 0) : Filter(name, state) abstract class Text(name: String, state: String = "") : Filter(name, state) abstract class CheckBox(name: String, state: Boolean = false) : Filter(name, state) abstract class TriState(name: String, state: Int = STATE_IGNORE) : Filter(name, state) { @@ -17,9 +17,24 @@ sealed class Filter(val name: String, var state: T) { const val STATE_EXCLUDE = 2 } } + abstract class Group(name: String, state: List): Filter>(name, state) - abstract class Sort(name: String, val values: Array, state: Selection? = null) + abstract class Sort(name: String, val values: Array, state: Selection? = null) : Filter(name, state) { data class Selection(val index: Int, val ascending: Boolean) } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is Filter<*>) return false + + return name == other.name && state == other.state + } + + override fun hashCode(): Int { + var result = name.hashCode() + result = 31 * result + (state?.hashCode() ?: 0) + return result + } + } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/model/FilterList.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/model/FilterList.kt index 9a64683c4..3137a66b4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/model/FilterList.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/model/FilterList.kt @@ -1,14 +1,7 @@ package eu.kanade.tachiyomi.data.source.model -class FilterList(list: List>) : List> by list { +data class FilterList(val list: List>) : List> by list { constructor(vararg fs: Filter<*>) : this(if (fs.isNotEmpty()) fs.asList() else emptyList()) - fun hasSameState(other: FilterList): Boolean { - if (size != other.size) return false - - return (0..lastIndex) - .all { get(it).javaClass == other[it].javaClass && get(it).state == other[it].state } - } - } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt index 8a433bb6f..ab8d4e539 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt @@ -99,7 +99,7 @@ class Batoto : ParsedOnlineSource(), LoginSource { is TextField -> { if (!filter.state.isEmpty()) url.addQueryParameter(filter.key, filter.state) } - is ListField -> { + is SelectField -> { val sel = filter.values[filter.state].value if (!sel.isEmpty()) url.addQueryParameter(filter.key, sel) } @@ -290,9 +290,9 @@ class Batoto : ParsedOnlineSource(), LoginSource { private class Status : Filter.TriState("Completed") private class Genre(name: String, val id: Int) : Filter.TriState(name) private class TextField(name: String, val key: String) : Filter.Text(name) - private class ListField(name: String, val key: String, values: Array, state: Int = 0) : Filter.List(name, values, state) + private class SelectField(name: String, val key: String, values: Array, state: Int = 0) : Filter.Select(name, values, state) private class Flag(name: String, val key: String, val valTrue: String, val valFalse: String) : Filter.CheckBox(name) - private class OrderBy() : Filter.Sort("Order by", + private class OrderBy() : Filter.Sort("Order by", arrayOf("Title", "Author", "Artist", "Rating", "Views", "Last Update"), Filter.Sort.Selection(4, false)) @@ -302,14 +302,14 @@ class Batoto : ParsedOnlineSource(), LoginSource { // on https://bato.to/search override fun getFilterList() = FilterList( TextField("Author", "artist_name"), - ListField("Type", "type", arrayOf(ListValue("Any", ""), ListValue("Manga (Jp)", "jp"), ListValue("Manhwa (Kr)", "kr"), ListValue("Manhua (Cn)", "cn"), ListValue("Artbook", "ar"), ListValue("Other", "ot"))), + SelectField("Type", "type", arrayOf(ListValue("Any", ""), ListValue("Manga (Jp)", "jp"), ListValue("Manhwa (Kr)", "kr"), ListValue("Manhua (Cn)", "cn"), ListValue("Artbook", "ar"), ListValue("Other", "ot"))), Status(), Flag("Exclude mature", "mature", "m", ""), Filter.Separator(), OrderBy(), Filter.Separator(), Filter.Header("Genres"), - ListField("Inclusion mode", "genre_cond", arrayOf(ListValue("And (all selected genres)", "and"), ListValue("Or (any selected genres) ", "or"))), + SelectField("Inclusion mode", "genre_cond", arrayOf(ListValue("And (all selected genres)", "and"), ListValue("Or (any selected genres) ", "or"))), Genre("4-Koma", 40), Genre("Action", 1), Genre("Adventure", 2), diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt index 6f3719c20..3b3add67a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt @@ -58,7 +58,12 @@ class Mangafox : ParsedOnlineSource() { val url = HttpUrl.parse("$baseUrl/search.php?name_method=cw&author_method=cw&artist_method=cw&advopts=1").newBuilder().addQueryParameter("name", query) (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> when (filter) { - is Genre -> url.addQueryParameter(filter.id, filter.state.toString()) + is Status -> url.addQueryParameter(filter.id, filter.state.toString()) + is GenreList -> { + filter.state.forEach { genre -> + url.addQueryParameter(genre.id, genre.state.toString()) + } + } is TextField -> url.addQueryParameter(filter.key, filter.state) is Type -> url.addQueryParameter("type", if(filter.state == 0) "" else filter.state.toString()) is OrderBy -> { @@ -161,24 +166,29 @@ class Mangafox : ParsedOnlineSource() { } } + private class Status(val id: String = "is_completed") : Filter.TriState("Completed") private class Genre(name: String, val id: String = "genres[$name]") : Filter.TriState(name) private class TextField(name: String, val key: String) : Filter.Text(name) - private class Type() : Filter.List("Type", arrayOf("Any", "Japanese Manga", "Korean Manhwa", "Chinese Manhua")) - private class OrderBy() : Filter.Sort("Order by", + private class Type : Filter.Select("Type", arrayOf("Any", "Japanese Manga", "Korean Manhwa", "Chinese Manhua")) + private class OrderBy : Filter.Sort("Order by", arrayOf("Series name", "Rating", "Views", "Total chapters", "Last chapter"), Filter.Sort.Selection(2, false)) + private class GenreList(genres: List) : Filter.Group("Genres", genres) - // $('select.genres').map((i,el)=>`Genre("${$(el).next().text().trim()}", "${$(el).attr('name')}")`).get().join(',\n') - // on http://mangafox.me/search.php override fun getFilterList() = FilterList( TextField("Author", "author"), TextField("Artist", "artist"), Type(), - Genre("Completed", "is_completed"), + Status(), Filter.Separator(), OrderBy(), Filter.Separator(), - Filter.Header("Genres"), + GenreList(getGenreList()) + ) + + // $('select.genres').map((i,el)=>`Genre("${$(el).next().text().trim()}", "${$(el).attr('name')}")`).get().join(',\n') + // on http://mangafox.me/search.php + private fun getGenreList() = listOf( Genre("Action"), Genre("Adult"), Genre("Adventure"), diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangahere.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangahere.kt index b0974b25c..1dfb308fc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangahere.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangahere.kt @@ -162,15 +162,11 @@ class Mangahere : ParsedOnlineSource() { override fun imageUrlParse(document: Document) = document.getElementById("image").attr("src") - private data class ListValue(val name: String, val value: String) { - override fun toString(): String = name - } - - private class Status() : Filter.TriState("Completed") + private class Status : Filter.TriState("Completed") private class Genre(name: String, val id: String = "genres[$name]") : Filter.TriState(name) private class TextField(name: String, val key: String) : Filter.Text(name) - private class Type() : Filter.List("Type", arrayOf("Any", "Japanese Manga (read from right to left)", "Korean Manhwa (read from left to right)")) - private class OrderBy() : Filter.Sort("Order by", + private class Type : Filter.Select("Type", arrayOf("Any", "Japanese Manga (read from right to left)", "Korean Manhwa (read from left to right)")) + private class OrderBy : Filter.Sort("Order by", arrayOf("Series name", "Rating", "Views", "Total chapters", "Last chapter"), Filter.Sort.Selection(2, false)) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangasee.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangasee.kt index e7422104f..b85f20dd6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangasee.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangasee.kt @@ -60,7 +60,7 @@ class Mangasee : ParsedOnlineSource() { if (filter.state?.ascending != true) url.addQueryParameter("sortOrder", "descending") } - is ListField -> if (filter.state != 0) url.addQueryParameter(filter.key, filter.values[filter.state]) + is SelectField -> if (filter.state != 0) url.addQueryParameter(filter.key, filter.values[filter.state]) is TextField -> if (!filter.state.isEmpty()) url.addQueryParameter(filter.key, filter.state) is Genre -> when (filter.state) { Filter.TriState.STATE_INCLUDE -> genres = if (genres == null) filter.name else genres + "," + filter.name @@ -155,23 +155,19 @@ class Mangasee : ParsedOnlineSource() { override fun imageUrlParse(document: Document): String = document.select("img.CurImage").attr("src") - private data class SortOption(val name: String, val keys: Array, val values: Array) { - override fun toString(): String = name - } - - private class Sort() : Filter.Sort("Sort", arrayOf("Alphabetically", "Date updated", "Popularity"), Filter.Sort.Selection(2, false)) + private class Sort : Filter.Sort("Sort", arrayOf("Alphabetically", "Date updated", "Popularity"), Filter.Sort.Selection(2, false)) private class Genre(name: String) : Filter.TriState(name) private class TextField(name: String, val key: String) : Filter.Text(name) - private class ListField(name: String, val key: String, values: Array, state: Int = 0) : Filter.List(name, values, state) + private class SelectField(name: String, val key: String, values: Array, state: Int = 0) : Filter.Select(name, values, state) // [...document.querySelectorAll("label.triStateCheckBox input")].map(el => `Filter("${el.getAttribute('name')}", "${el.nextSibling.textContent.trim()}")`).join(',\n') // http://mangasee.co/advanced-search/ override fun getFilterList() = FilterList( TextField("Years", "year"), TextField("Author", "author"), - ListField("Scan Status", "status", arrayOf("Any", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing")), - ListField("Publish Status", "pstatus", arrayOf("Any", "Cancelled", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing", "Unfinished")), - ListField("Type", "type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")), + SelectField("Scan Status", "status", arrayOf("Any", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing")), + SelectField("Publish Status", "pstatus", arrayOf("Any", "Cancelled", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing", "Unfinished")), + SelectField("Type", "type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")), Filter.Separator(), Sort(), Filter.Separator(), diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Readmangatoday.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Readmangatoday.kt index fae5bf4da..7175b3aa9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Readmangatoday.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Readmangatoday.kt @@ -164,7 +164,7 @@ class Readmangatoday : ParsedOnlineSource() { private class Status() : Filter.TriState("Completed") private class Genre(name: String, val id: Int) : Filter.TriState(name) private class TextField(name: String, val key: String) : Filter.Text(name) - private class Type() : Filter.List("Type", arrayOf("All", "Japanese Manga", "Korean Manhwa", "Chinese Manhua")) + private class Type() : Filter.Select("Type", arrayOf("All", "Japanese Manga", "Korean Manhwa", "Chinese Manhua")) // [...document.querySelectorAll("ul.manga-cat span")].map(el => `Genre("${el.nextSibling.textContent.trim()}", ${el.getAttribute('data-id')})`).join(',\n') // http://www.readmanga.today/advanced-search diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt index 36ff18840..36228ec07 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt @@ -237,10 +237,10 @@ open class CatalogueFragment : BaseRxFragment(), 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 = { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt index 702fdada1..2677cce3a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt @@ -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>(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() { - - 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(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(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) } } \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/CheckboxItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/CheckboxItem.kt new file mode 100644 index 000000000..5e27cc824 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/CheckboxItem.kt @@ -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() { + + 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?) { + 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 + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt new file mode 100644 index 000000000..2ca1c67c2 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt @@ -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>() { + + 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?) { + 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 + } + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/HeaderItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/HeaderItem.kt new file mode 100644 index 000000000..6e7b27f48 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/HeaderItem.kt @@ -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() { + + @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?) { + 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) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SectionItems.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SectionItems.kt new file mode 100644 index 000000000..0470f6beb --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SectionItems.kt @@ -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 { + + 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 { + + 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 { + + 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 { + + private var head: GroupItem? = null + + override fun getHeader(): GroupItem? = head + + override fun setHeader(header: GroupItem?) { + head = header + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SelectItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SelectItem.kt new file mode 100644 index 000000000..e9a10d535 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SelectItem.kt @@ -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() { + + 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?) { + holder.text.text = filter.name + ": " + + val spinner = holder.spinner + spinner.prompt = filter.name + spinner.adapter = ArrayAdapter(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 + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SeparatorItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SeparatorItem.kt new file mode 100644 index 000000000..906834e75 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SeparatorItem.kt @@ -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() { + + @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?) { + + } + + 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) +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt new file mode 100644 index 000000000..b97c71abf --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt @@ -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>() { + + 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?) { + 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 + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt new file mode 100644 index 000000000..008e4524a --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt @@ -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(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?) { + 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 + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TextItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TextItem.kt new file mode 100644 index 000000000..e700520ff --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TextItem.kt @@ -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() { + + 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?) { + 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 + } +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TriStateItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TriStateItem.kt new file mode 100644 index 000000000..d08173e4b --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/TriStateItem.kt @@ -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() { + + 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?) { + 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 + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt index 899ca65a3..5f3b89fee 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryAdapter.kt @@ -17,7 +17,6 @@ class CategoryAdapter(private val activity: CategoryActivity) : * Called when item is released. */ fun onItemReleased() { - // Update database activity.onItemReleased() } diff --git a/app/src/main/res/drawable/ic_chevron_right_white_24dp.xml b/app/src/main/res/drawable/ic_chevron_right_white_24dp.xml new file mode 100644 index 000000000..36b411ace --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_right_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_expand_more_white_24dp.xml b/app/src/main/res/drawable/ic_expand_more_white_24dp.xml new file mode 100644 index 000000000..fd3ce4a46 --- /dev/null +++ b/app/src/main/res/drawable/ic_expand_more_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/catalogue_drawer_content.xml b/app/src/main/res/layout/catalogue_drawer_content.xml index 62d4a9803..1eced0573 100644 --- a/app/src/main/res/layout/catalogue_drawer_content.xml +++ b/app/src/main/res/layout/catalogue_drawer_content.xml @@ -25,4 +25,8 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/navigation_view_group.xml b/app/src/main/res/layout/navigation_view_group.xml new file mode 100644 index 000000000..10b43e851 --- /dev/null +++ b/app/src/main/res/layout/navigation_view_group.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/navigation_view_sort.xml b/app/src/main/res/layout/navigation_view_sort.xml new file mode 100644 index 000000000..d3399c50f --- /dev/null +++ b/app/src/main/res/layout/navigation_view_sort.xml @@ -0,0 +1,30 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/navigation_view_sort_item.xml b/app/src/main/res/layout/navigation_view_sort_item.xml new file mode 100644 index 000000000..7358b6f29 --- /dev/null +++ b/app/src/main/res/layout/navigation_view_sort_item.xml @@ -0,0 +1,21 @@ + + + + + +