Complete group filters

This commit is contained in:
len 2017-01-15 17:04:31 +01:00
parent e76fb7a524
commit 71ab6d38e4
18 changed files with 217 additions and 193 deletions

View File

@ -93,8 +93,18 @@ class Batoto : ParsedOnlineSource(), LoginSource {
is Status -> if (!filter.isIgnored()) {
url.addQueryParameter("completed", if (filter.isExcluded()) "i" else "c")
}
is Genre -> if (!filter.isIgnored()) {
genres += (if (filter.isExcluded()) ";e" else ";i") + filter.id
is GenreList -> {
filter.state.forEach { filter ->
when (filter) {
is Genre -> if (!filter.isIgnored()) {
genres += (if (filter.isExcluded()) ";e" else ";i") + filter.id
}
is SelectField -> {
val sel = filter.values[filter.state].value
if (!sel.isEmpty()) url.addQueryParameter(filter.key, sel)
}
}
}
}
is TextField -> {
if (!filter.state.isEmpty()) url.addQueryParameter(filter.key, filter.state)
@ -292,23 +302,25 @@ class Batoto : ParsedOnlineSource(), LoginSource {
private class TextField(name: String, val key: String) : Filter.Text(name)
private class SelectField(name: String, val key: String, values: Array<ListValue>, state: Int = 0) : Filter.Select<ListValue>(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 GenreList(genres: List<Filter<*>>) : Filter.Group<Filter<*>>("Genres", genres)
private class OrderBy : Filter.Sort("Order by",
arrayOf("Title", "Author", "Artist", "Rating", "Views", "Last Update"),
Filter.Sort.Selection(4, false))
// [...document.querySelectorAll("#advanced_options div.genre_buttons")].map((el,i) => {
// const onClick=el.getAttribute('onclick');const id=onClick.substr(14,onClick.length-16);return `Genre("${el.textContent.trim()}", ${id})`
// }).join(',\n')
// on https://bato.to/search
override fun getFilterList() = FilterList(
TextField("Author", "artist_name"),
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"),
GenreList(getGenreList())
)
// [...document.querySelectorAll("#advanced_options div.genre_buttons")].map((el,i) => {
// const onClick=el.getAttribute('onclick');const id=onClick.substr(14,onClick.length-16);return `Genre("${el.textContent.trim()}", ${id})`
// }).join(',\n')
// on https://bato.to/search
private fun getGenreList() = listOf(
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),

View File

@ -64,7 +64,7 @@ class Kissmanga : ParsedOnlineSource() {
when (filter) {
is Author -> add("authorArtist", filter.state)
is Status -> add("status", arrayOf("", "Completed", "Ongoing")[filter.state])
is Genre -> add("genres", filter.state.toString())
is GenreList -> filter.state.forEach { genre -> add("genres", genre.state.toString()) }
}
}
}
@ -134,16 +134,20 @@ class Kissmanga : ParsedOnlineSource() {
override fun imageUrlParse(document: Document) = ""
private class Status() : Filter.TriState("Completed")
private class Author() : Filter.Text("Author")
private class Status : Filter.TriState("Completed")
private class Author : Filter.Text("Author")
private class Genre(name: String) : Filter.TriState(name)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
// $("select[name=\"genres\"]").map((i,el) => `Genre("${$(el).next().text().trim()}", ${i})`).get().join(',\n')
// on http://kissmanga.com/AdvanceSearch
override fun getFilterList() = FilterList(
Author(),
Status(),
Filter.Header("Genres"),
GenreList(getGenreList())
)
// $("select[name=\"genres\"]").map((i,el) => `Genre("${$(el).next().text().trim()}", ${i})`).get().join(',\n')
// on http://kissmanga.com/AdvanceSearch
private fun getGenreList() = listOf(
Genre("4-Koma"),
Genre("Action"),
Genre("Adult"),

View File

@ -59,11 +59,7 @@ class Mangafox : ParsedOnlineSource() {
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is Status -> url.addQueryParameter(filter.id, filter.state.toString())
is GenreList -> {
filter.state.forEach { genre ->
url.addQueryParameter(genre.id, genre.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 -> {
@ -180,9 +176,7 @@ class Mangafox : ParsedOnlineSource() {
TextField("Artist", "artist"),
Type(),
Status(),
Filter.Separator(),
OrderBy(),
Filter.Separator(),
GenreList(getGenreList())
)

View File

@ -61,7 +61,7 @@ class Mangahere : ParsedOnlineSource() {
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is Status -> url.addQueryParameter("is_completed", arrayOf("", "1", "0")[filter.state])
is Genre -> 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("direction", arrayOf("", "rl", "lr")[filter.state])
is OrderBy -> {
@ -169,18 +169,20 @@ class Mangahere : ParsedOnlineSource() {
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<Genre>) : Filter.Group<Genre>("Genres", genres)
// [...document.querySelectorAll("select[id^='genres'")].map((el,i) => `Genre("${el.nextSibling.nextSibling.textContent.trim()}", "${el.getAttribute('name')}")`).join(',\n')
// http://www.mangahere.co/advsearch.htm
override fun getFilterList() = FilterList(
TextField("Author", "author"),
TextField("Artist", "artist"),
Type(),
Status(),
Filter.Separator(),
OrderBy(),
Filter.Separator(),
Filter.Header("Genres"),
GenreList(getGenreList())
)
// [...document.querySelectorAll("select[id^='genres'")].map((el,i) => `Genre("${el.nextSibling.nextSibling.textContent.trim()}", "${el.getAttribute('name')}")`).join(',\n')
// http://www.mangahere.co/advsearch.htm
private fun getGenreList() = listOf(
Genre("Action"),
Genre("Adventure"),
Genre("Comedy"),

View File

@ -50,8 +50,8 @@ class Mangasee : ParsedOnlineSource() {
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = HttpUrl.parse("$baseUrl/search/request.php").newBuilder()
if (!query.isEmpty()) url.addQueryParameter("keyword", query)
var genres: String? = null
var genresNo: String? = null
val genres = mutableListOf<String>()
val genresNo = mutableListOf<String>()
for (filter in if (filters.isEmpty()) getFilterList() else filters) {
when (filter) {
is Sort -> {
@ -62,14 +62,16 @@ class Mangasee : ParsedOnlineSource() {
}
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
Filter.TriState.STATE_EXCLUDE -> genresNo = if (genresNo == null) filter.name else genresNo + "," + filter.name
is GenreList -> filter.state.forEach { genre ->
when (genre.state) {
Filter.TriState.STATE_INCLUDE -> genres.add(genre.name)
Filter.TriState.STATE_EXCLUDE -> genresNo.add(genre.name)
}
}
}
}
if (genres != null) url.addQueryParameter("genre", genres)
if (genresNo != null) url.addQueryParameter("genreNo", genresNo)
if (genres.isNotEmpty()) url.addQueryParameter("genre", genres.joinToString(","))
if (genresNo.isNotEmpty()) url.addQueryParameter("genreNo", genresNo.joinToString(","))
val (body, requestUrl) = convertQueryToPost(page, url.toString())
return POST(requestUrl, headers, body.build())
@ -155,23 +157,51 @@ class Mangasee : ParsedOnlineSource() {
override fun imageUrlParse(document: Document): String = document.select("img.CurImage").attr("src")
override fun latestUpdatesNextPageSelector() = "button.requestMore"
override fun latestUpdatesSelector(): String = "a.latestSeries"
override fun latestUpdatesRequest(page: Int): Request {
val url = "http://mangaseeonline.net/home/latest.request.php"
val (body, requestUrl) = convertQueryToPost(page, url)
return POST(requestUrl, headers, body.build())
}
override fun latestUpdatesFromElement(element: Element): SManga {
val manga = SManga.create()
element.select("a.latestSeries").first().let {
val chapterUrl = it.attr("href")
val indexOfMangaUrl = chapterUrl.indexOf("-chapter-")
val indexOfLastPath = chapterUrl.lastIndexOf("/")
val mangaUrl = chapterUrl.substring(indexOfLastPath, indexOfMangaUrl)
val defaultText = it.select("p.clamp2").text()
val m = recentUpdatesPattern.matcher(defaultText)
val title = if (m.matches()) m.group(1) else defaultText
manga.setUrlWithoutDomain("/manga" + mangaUrl)
manga.title = title
}
return manga
}
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 SelectField(name: String, val key: String, values: Array<String>, state: Int = 0) : Filter.Select<String>(name, values, state)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
// [...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"),
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(),
Filter.Header("Genres"),
GenreList(getGenreList())
)
// [...document.querySelectorAll("label.triStateCheckBox input")].map(el => `Filter("${el.getAttribute('name')}", "${el.nextSibling.textContent.trim()}")`).join(',\n')
// http://mangasee.co/advanced-search/
private fun getGenreList() = listOf(
Genre("Action"),
Genre("Adult"),
Genre("Adventure"),
@ -210,30 +240,4 @@ class Mangasee : ParsedOnlineSource() {
Genre("Yuri")
)
override fun latestUpdatesNextPageSelector() = "button.requestMore"
override fun latestUpdatesSelector(): String = "a.latestSeries"
override fun latestUpdatesRequest(page: Int): Request {
val url = "http://mangaseeonline.net/home/latest.request.php"
val (body, requestUrl) = convertQueryToPost(page, url)
return POST(requestUrl, headers, body.build())
}
override fun latestUpdatesFromElement(element: Element): SManga {
val manga = SManga.create()
element.select("a.latestSeries").first().let {
val chapterUrl = it.attr("href")
val indexOfMangaUrl = chapterUrl.indexOf("-chapter-")
val indexOfLastPath = chapterUrl.lastIndexOf("/")
val mangaUrl = chapterUrl.substring(indexOfLastPath, indexOfMangaUrl)
val defaultText = it.select("p.clamp2").text()
val m = recentUpdatesPattern.matcher(defaultText)
val title = if (m.matches()) m.group(1) else defaultText
manga.setUrlWithoutDomain("/manga" + mangaUrl)
manga.title = title
}
return manga
}
}

View File

@ -70,9 +70,11 @@ class Readmangatoday : ParsedOnlineSource() {
is TextField -> builder.add(filter.key, filter.state)
is Type -> builder.add("type", arrayOf("all", "japanese", "korean", "chinese")[filter.state])
is Status -> builder.add("status", arrayOf("both", "completed", "ongoing")[filter.state])
is Genre -> when (filter.state) {
Filter.TriState.STATE_INCLUDE -> builder.add("include[]", filter.id.toString())
Filter.TriState.STATE_EXCLUDE -> builder.add("exclude[]", filter.id.toString())
is GenreList -> filter.state.forEach { genre ->
when (genre.state) {
Filter.TriState.STATE_INCLUDE -> builder.add("include[]", genre.id.toString())
Filter.TriState.STATE_EXCLUDE -> builder.add("exclude[]", genre.id.toString())
}
}
}
}
@ -161,19 +163,23 @@ class Readmangatoday : ParsedOnlineSource() {
override fun imageUrlParse(document: Document) = document.select("img.img-responsive-2").first().attr("src")
private class Status() : Filter.TriState("Completed")
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.Select<String>("Type", arrayOf("All", "Japanese Manga", "Korean Manhwa", "Chinese Manhua"))
private class Type : Filter.Select<String>("Type", arrayOf("All", "Japanese Manga", "Korean Manhwa", "Chinese Manhua"))
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
// [...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
override fun getFilterList() = FilterList(
TextField("Author", "author-name"),
TextField("Artist", "artist-name"),
Type(),
Status(),
Filter.Header("Genres"),
GenreList(getGenreList())
)
// [...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
private fun getGenreList() = listOf(
Genre("Action", 2),
Genre("Adventure", 4),
Genre("Comedy", 5),

View File

@ -208,7 +208,7 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
showProgressBar()
adapter.clear()
presenter.setActiveSource(source)
navView?.setFilters(presenter.sourceFilters)
navView?.setFilters(presenter.filterItems)
activity.invalidateOptionsMenu()
}
}
@ -229,7 +229,7 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
this.navView = navView
activity.drawer.addView(navView)
activity.drawer.addDrawerListener(drawerListener)
navView.setFilters(presenter.sourceFilters)
navView.setFilters(presenter.filterItems)
navView.post {
if (isAdded && !activity.drawer.isDrawerOpen(navView))
@ -247,7 +247,7 @@ open class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleVie
presenter.appliedFilters = FilterList()
val newFilters = presenter.source.getFilterList()
presenter.sourceFilters = newFilters
navView.setFilters(newFilters)
navView.setFilters(presenter.filterItems)
}
showProgressBar()

View File

@ -5,11 +5,7 @@ import android.util.AttributeSet
import android.view.ViewGroup
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.ui.catalogue.filter.*
import eu.kanade.tachiyomi.util.inflate
import eu.kanade.tachiyomi.widget.SimpleNavigationView
import kotlinx.android.synthetic.main.catalogue_drawer_content.view.*
@ -18,7 +14,9 @@ import kotlinx.android.synthetic.main.catalogue_drawer_content.view.*
class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
: SimpleNavigationView(context, attrs) {
val adapter = FlexibleAdapter<IFlexible<*>>(null)
val adapter: FlexibleAdapter<IFlexible<*>> = FlexibleAdapter<IFlexible<*>>(null)
.setDisplayHeadersAtStartUp(true)
.setStickyHeaders(true)
var onSearchClicked = {}
@ -26,53 +24,17 @@ class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs:
init {
recycler.adapter = adapter
recycler.setHasFixedSize(true)
val view = inflate(R.layout.catalogue_drawer_content)
((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(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)
fun setFilters(items: List<IFlexible<*>>) {
adapter.updateDataSet(items.toMutableList())
}
}

View File

@ -1,6 +1,8 @@
package eu.kanade.tachiyomi.ui.catalogue
import android.os.Bundle
import eu.davidea.flexibleadapter.items.IFlexible
import eu.davidea.flexibleadapter.items.ISectionable
import eu.kanade.tachiyomi.data.cache.CoverCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.database.models.Manga
@ -9,10 +11,12 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.data.source.CatalogueSource
import eu.kanade.tachiyomi.data.source.Source
import eu.kanade.tachiyomi.data.source.SourceManager
import eu.kanade.tachiyomi.data.source.model.Filter
import eu.kanade.tachiyomi.data.source.model.FilterList
import eu.kanade.tachiyomi.data.source.model.SManga
import eu.kanade.tachiyomi.data.source.online.LoginSource
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.catalogue.filter.*
import rx.Observable
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
@ -68,6 +72,12 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() {
* Modifiable list of filters.
*/
var sourceFilters = FilterList()
set(value) {
field = value
filterItems = value.toItems()
}
var filterItems: List<IFlexible<*>> = emptyList()
/**
* List of filters used by the [Pager]. If empty alongside [query], the popular query is used.
@ -362,4 +372,41 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() {
return CataloguePager(source, query, filters)
}
private fun FilterList.toItems(): List<IFlexible<*>> {
return 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
}
}
}
}

View File

@ -44,7 +44,7 @@ class GroupItem(val filter: Filter.Group<*>) : AbstractExpandableHeaderItem<Grou
return filter.hashCode()
}
class Holder(view: View, adapter: FlexibleAdapter<*>) : ExpandableViewHolder(view, adapter, true) {
open 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

View File

@ -12,6 +12,18 @@ class TriStateSectionItem(filter: Filter.TriState) : TriStateItem(filter), ISect
override fun setHeader(header: GroupItem?) {
head = header
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is TriStateSectionItem) {
return filter == other.filter
}
return false
}
override fun hashCode(): Int {
return filter.hashCode()
}
}
class TextSectionItem(filter: Filter.Text) : TextItem(filter), ISectionable<TextItem.Holder, GroupItem> {
@ -23,6 +35,18 @@ class TextSectionItem(filter: Filter.Text) : TextItem(filter), ISectionable<Text
override fun setHeader(header: GroupItem?) {
head = header
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is TextSectionItem) {
return filter == other.filter
}
return false
}
override fun hashCode(): Int {
return filter.hashCode()
}
}
class CheckboxSectionItem(filter: Filter.CheckBox) : CheckboxItem(filter), ISectionable<CheckboxItem.Holder, GroupItem> {
@ -34,6 +58,18 @@ class CheckboxSectionItem(filter: Filter.CheckBox) : CheckboxItem(filter), ISect
override fun setHeader(header: GroupItem?) {
head = header
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is CheckboxSectionItem) {
return filter == other.filter
}
return false
}
override fun hashCode(): Int {
return filter.hashCode()
}
}
class SelectSectionItem(filter: Filter.Select<*>) : SelectItem(filter), ISectionable<SelectItem.Holder, GroupItem> {
@ -45,4 +81,16 @@ class SelectSectionItem(filter: Filter.Select<*>) : SelectItem(filter), ISection
override fun setHeader(header: GroupItem?) {
head = header
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is SelectSectionItem) {
return filter == other.filter
}
return false
}
override fun hashCode(): Int {
return filter.hashCode()
}
}

View File

@ -3,24 +3,22 @@ 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<*, *>>() {
// Use an id instead of the layout res to allow to reuse the layout.
override fun getLayoutRes(): Int {
return R.layout.navigation_view_sort
return R.id.catalogue_filter_sort_group
}
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
return Holder(inflater.inflate(R.layout.navigation_view_group, parent, false), adapter)
}
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {
@ -44,14 +42,5 @@ class SortGroup(val filter: Filter.Sort) : AbstractExpandableHeaderItem<SortGrou
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
}
}
class Holder(view: View, adapter: FlexibleAdapter<*>) : GroupItem.Holder(view, adapter)
}

View File

@ -15,12 +15,13 @@ import eu.kanade.tachiyomi.util.getResourceColor
class SortItem(val name: String, val group: SortGroup) : AbstractSectionableItem<SortItem.Holder, SortGroup>(group) {
// Use an id instead of the layout res to allow to reuse the layout.
override fun getLayoutRes(): Int {
return R.layout.navigation_view_sort_item
return R.id.catalogue_filter_sort_item
}
override fun createViewHolder(adapter: FlexibleAdapter<*>, inflater: LayoutInflater, parent: ViewGroup): Holder {
return Holder(inflater.inflate(layoutRes, parent, false), adapter)
return Holder(inflater.inflate(R.layout.navigation_view_checkedtext, parent, false), adapter)
}
override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

View File

@ -92,7 +92,7 @@ class CategoryActivity :
*/
fun setCategories(categories: List<CategoryItem>) {
actionMode?.finish()
adapter.updateDataSet(categories)
adapter.updateDataSet(categories.toMutableList())
val selected = categories.filter { it.isSelected }
if (selected.isNotEmpty()) {
selected.forEach { onItemLongClick(categories.indexOf(it)) }

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeightSmall"
android:background="?colorPrimary"
android:orientation="horizontal"
android:gravity="center_vertical"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:elevation="2dp">
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="@color/textColorPrimaryDark"
tools:text="Header"/>
<ImageView
android:id="@+id/expand_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="?attr/listPreferredItemHeightSmall"
android:paddingLeft="?attr/listPreferredItemPaddingLeft"
android:paddingRight="?attr/listPreferredItemPaddingRight"
android:background="?attr/selectableItemBackground"
android:focusable="true">
<CheckedTextView
android:id="@+id/nav_view_item"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawablePadding="@dimen/material_component_lists_icon_left_padding"
android:gravity="center_vertical|start"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Body2" />
</LinearLayout>

View File

@ -15,7 +15,7 @@
android:layout_weight="1"
android:gravity="center_vertical|start">
<EditText
<android.support.design.widget.TextInputEditText
android:id="@+id/nav_view_item"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="catalogue_filter_sort_group" type="id"/>
<item name="catalogue_filter_sort_item" type="id"/>
</resources>