Browse Source

Complete group filters

len 8 years ago
parent
commit
71ab6d38e4

+ 22 - 10
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Batoto.kt

@@ -93,8 +93,18 @@ class Batoto : ParsedOnlineSource(), LoginSource {
                 is Status -> if (!filter.isIgnored()) {
                 is Status -> if (!filter.isIgnored()) {
                     url.addQueryParameter("completed", if (filter.isExcluded()) "i" else "c")
                     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 -> {
                 is TextField -> {
                     if (!filter.state.isEmpty()) url.addQueryParameter(filter.key, filter.state)
                     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 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 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 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"),
             arrayOf("Title", "Author", "Artist", "Rating", "Views", "Last Update"),
             Filter.Sort.Selection(4, false))
             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(
     override fun getFilterList() = FilterList(
             TextField("Author", "artist_name"),
             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"))),
             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(),
             Status(),
             Flag("Exclude mature", "mature", "m", ""),
             Flag("Exclude mature", "mature", "m", ""),
-            Filter.Separator(),
             OrderBy(),
             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"))),
             SelectField("Inclusion mode", "genre_cond", arrayOf(ListValue("And (all selected genres)", "and"), ListValue("Or (any selected genres) ", "or"))),
             Genre("4-Koma", 40),
             Genre("4-Koma", 40),
             Genre("Action", 1),
             Genre("Action", 1),

+ 10 - 6
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Kissmanga.kt

@@ -64,7 +64,7 @@ class Kissmanga : ParsedOnlineSource() {
                 when (filter) {
                 when (filter) {
                     is Author -> add("authorArtist", filter.state)
                     is Author -> add("authorArtist", filter.state)
                     is Status -> add("status", arrayOf("", "Completed", "Ongoing")[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) = ""
     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 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(
     override fun getFilterList() = FilterList(
             Author(),
             Author(),
             Status(),
             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("4-Koma"),
             Genre("Action"),
             Genre("Action"),
             Genre("Adult"),
             Genre("Adult"),

+ 1 - 7
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangafox.kt

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

+ 8 - 6
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangahere.kt

@@ -61,7 +61,7 @@ class Mangahere : ParsedOnlineSource() {
         (if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
         (if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
             when (filter) {
             when (filter) {
                 is Status -> url.addQueryParameter("is_completed", arrayOf("", "1", "0")[filter.state])
                 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 TextField -> url.addQueryParameter(filter.key, filter.state)
                 is Type -> url.addQueryParameter("direction", arrayOf("", "rl", "lr")[filter.state])
                 is Type -> url.addQueryParameter("direction", arrayOf("", "rl", "lr")[filter.state])
                 is OrderBy -> {
                 is OrderBy -> {
@@ -169,18 +169,20 @@ class Mangahere : ParsedOnlineSource() {
     private class OrderBy : Filter.Sort("Order by",
     private class OrderBy : Filter.Sort("Order by",
             arrayOf("Series name", "Rating", "Views", "Total chapters", "Last chapter"),
             arrayOf("Series name", "Rating", "Views", "Total chapters", "Last chapter"),
             Filter.Sort.Selection(2, false))
             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(
     override fun getFilterList() = FilterList(
             TextField("Author", "author"),
             TextField("Author", "author"),
             TextField("Artist", "artist"),
             TextField("Artist", "artist"),
             Type(),
             Type(),
             Status(),
             Status(),
-            Filter.Separator(),
             OrderBy(),
             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("Action"),
             Genre("Adventure"),
             Genre("Adventure"),
             Genre("Comedy"),
             Genre("Comedy"),

+ 42 - 38
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Mangasee.kt

@@ -50,8 +50,8 @@ class Mangasee : ParsedOnlineSource() {
     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
     override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
         val url = HttpUrl.parse("$baseUrl/search/request.php").newBuilder()
         val url = HttpUrl.parse("$baseUrl/search/request.php").newBuilder()
         if (!query.isEmpty()) url.addQueryParameter("keyword", query)
         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) {
         for (filter in if (filters.isEmpty()) getFilterList() else filters) {
             when (filter) {
             when (filter) {
                 is Sort -> {
                 is Sort -> {
@@ -62,14 +62,16 @@ class Mangasee : ParsedOnlineSource() {
                 }
                 }
                 is SelectField -> 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 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())
         val (body, requestUrl) = convertQueryToPost(page, url.toString())
         return POST(requestUrl, headers, body.build())
         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 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 Sort : Filter.Sort("Sort", arrayOf("Alphabetically", "Date updated", "Popularity"), Filter.Sort.Selection(2, false))
     private class Genre(name: String) : Filter.TriState(name)
     private class Genre(name: String) : Filter.TriState(name)
     private class TextField(name: String, val key: String) : Filter.Text(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 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(
     override fun getFilterList() = FilterList(
             TextField("Years", "year"),
             TextField("Years", "year"),
             TextField("Author", "author"),
             TextField("Author", "author"),
             SelectField("Scan Status", "status", arrayOf("Any", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing")),
             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("Publish Status", "pstatus", arrayOf("Any", "Cancelled", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing", "Unfinished")),
             SelectField("Type", "type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")),
             SelectField("Type", "type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")),
-            Filter.Separator(),
             Sort(),
             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("Action"),
             Genre("Adult"),
             Genre("Adult"),
             Genre("Adventure"),
             Genre("Adventure"),
@@ -210,30 +240,4 @@ class Mangasee : ParsedOnlineSource() {
             Genre("Yuri")
             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
-    }
-
 }
 }

+ 14 - 8
app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/Readmangatoday.kt

@@ -70,9 +70,11 @@ class Readmangatoday : ParsedOnlineSource() {
                 is TextField -> builder.add(filter.key, filter.state)
                 is TextField -> builder.add(filter.key, filter.state)
                 is Type -> builder.add("type", arrayOf("all", "japanese", "korean", "chinese")[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 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")
     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 Genre(name: String, val id: Int) : Filter.TriState(name)
     private class TextField(name: String, val key: String) : Filter.Text(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(
     override fun getFilterList() = FilterList(
             TextField("Author", "author-name"),
             TextField("Author", "author-name"),
             TextField("Artist", "artist-name"),
             TextField("Artist", "artist-name"),
             Type(),
             Type(),
             Status(),
             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("Action", 2),
             Genre("Adventure", 4),
             Genre("Adventure", 4),
             Genre("Comedy", 5),
             Genre("Comedy", 5),

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt

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

+ 6 - 44
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueNavigationView.kt

@@ -5,11 +5,7 @@ import android.util.AttributeSet
 import android.view.ViewGroup
 import android.view.ViewGroup
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.IFlexible
 import eu.davidea.flexibleadapter.items.IFlexible
-import eu.davidea.flexibleadapter.items.ISectionable
 import eu.kanade.tachiyomi.R
 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.util.inflate
 import eu.kanade.tachiyomi.widget.SimpleNavigationView
 import eu.kanade.tachiyomi.widget.SimpleNavigationView
 import kotlinx.android.synthetic.main.catalogue_drawer_content.view.*
 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)
 class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
     : SimpleNavigationView(context, attrs) {
     : SimpleNavigationView(context, attrs) {
 
 
-    val adapter = FlexibleAdapter<IFlexible<*>>(null)
+    val adapter: FlexibleAdapter<IFlexible<*>> = FlexibleAdapter<IFlexible<*>>(null)
+            .setDisplayHeadersAtStartUp(true)
+            .setStickyHeaders(true)
 
 
     var onSearchClicked = {}
     var onSearchClicked = {}
 
 
@@ -26,53 +24,17 @@ class CatalogueNavigationView @JvmOverloads constructor(context: Context, attrs:
 
 
     init {
     init {
         recycler.adapter = adapter
         recycler.adapter = adapter
+        recycler.setHasFixedSize(true)
         val view = inflate(R.layout.catalogue_drawer_content)
         val view = inflate(R.layout.catalogue_drawer_content)
         ((view as ViewGroup).getChildAt(1) as ViewGroup).addView(recycler)
         ((view as ViewGroup).getChildAt(1) as ViewGroup).addView(recycler)
         addView(view)
         addView(view)
 
 
         search_btn.setOnClickListener { onSearchClicked() }
         search_btn.setOnClickListener { onSearchClicked() }
         reset_btn.setOnClickListener { onResetClicked() }
         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())
     }
     }
 
 
 }
 }

+ 47 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt

@@ -1,6 +1,8 @@
 package eu.kanade.tachiyomi.ui.catalogue
 package eu.kanade.tachiyomi.ui.catalogue
 
 
 import android.os.Bundle
 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.cache.CoverCache
 import eu.kanade.tachiyomi.data.database.DatabaseHelper
 import eu.kanade.tachiyomi.data.database.DatabaseHelper
 import eu.kanade.tachiyomi.data.database.models.Manga
 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.CatalogueSource
 import eu.kanade.tachiyomi.data.source.Source
 import eu.kanade.tachiyomi.data.source.Source
 import eu.kanade.tachiyomi.data.source.SourceManager
 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.FilterList
 import eu.kanade.tachiyomi.data.source.model.SManga
 import eu.kanade.tachiyomi.data.source.model.SManga
 import eu.kanade.tachiyomi.data.source.online.LoginSource
 import eu.kanade.tachiyomi.data.source.online.LoginSource
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
 import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
+import eu.kanade.tachiyomi.ui.catalogue.filter.*
 import rx.Observable
 import rx.Observable
 import rx.Subscription
 import rx.Subscription
 import rx.android.schedulers.AndroidSchedulers
 import rx.android.schedulers.AndroidSchedulers
@@ -68,6 +72,12 @@ open class CataloguePresenter : BasePresenter<CatalogueFragment>() {
      * Modifiable list of filters.
      * Modifiable list of filters.
      */
      */
     var sourceFilters = FilterList()
     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.
      * 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)
         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
+            }
+        }
+    }
+
 }
 }

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/GroupItem.kt

@@ -44,7 +44,7 @@ class GroupItem(val filter: Filter.Group<*>) : AbstractExpandableHeaderItem<Grou
         return filter.hashCode()
         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 title = itemView.findViewById(R.id.title) as TextView
         val icon = itemView.findViewById(R.id.expand_icon) as ImageView
         val icon = itemView.findViewById(R.id.expand_icon) as ImageView

+ 48 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SectionItems.kt

@@ -12,6 +12,18 @@ class TriStateSectionItem(filter: Filter.TriState) : TriStateItem(filter), ISect
     override fun setHeader(header: GroupItem?) {
     override fun setHeader(header: GroupItem?) {
         head = header
         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> {
 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?) {
     override fun setHeader(header: GroupItem?) {
         head = header
         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> {
 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?) {
     override fun setHeader(header: GroupItem?) {
         head = header
         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> {
 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?) {
     override fun setHeader(header: GroupItem?) {
         head = header
         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()
+    }
 }
 }

+ 4 - 15
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortGroup.kt

@@ -3,24 +3,22 @@ package eu.kanade.tachiyomi.ui.catalogue.filter
 import android.view.LayoutInflater
 import android.view.LayoutInflater
 import android.view.View
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.TextView
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.FlexibleAdapter
 import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem
 import eu.davidea.flexibleadapter.items.AbstractExpandableHeaderItem
 import eu.davidea.flexibleadapter.items.ISectionable
 import eu.davidea.flexibleadapter.items.ISectionable
-import eu.davidea.viewholders.ExpandableViewHolder
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.source.model.Filter
 import eu.kanade.tachiyomi.data.source.model.Filter
 import eu.kanade.tachiyomi.util.setVectorCompat
 import eu.kanade.tachiyomi.util.setVectorCompat
 
 
 class SortGroup(val filter: Filter.Sort) : AbstractExpandableHeaderItem<SortGroup.Holder, ISectionable<*, *>>() {
 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 {
     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 {
     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?>?) {
     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()
         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)
 }
 }

+ 3 - 2
app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/filter/SortItem.kt

@@ -15,12 +15,13 @@ import eu.kanade.tachiyomi.util.getResourceColor
 
 
 class SortItem(val name: String, val group: SortGroup) : AbstractSectionableItem<SortItem.Holder, SortGroup>(group) {
 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 {
     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 {
     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?>?) {
     override fun bindViewHolder(adapter: FlexibleAdapter<*>, holder: Holder, position: Int, payloads: List<Any?>?) {

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/category/CategoryActivity.kt

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

+ 0 - 30
app/src/main/res/layout/navigation_view_sort.xml

@@ -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>

+ 0 - 21
app/src/main/res/layout/navigation_view_sort_item.xml

@@ -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>

+ 1 - 1
app/src/main/res/layout/navigation_view_text.xml

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

+ 6 - 0
app/src/main/res/values/ids.xml

@@ -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>