From fb3756420bcaf2ae568fff819ee3726e327e223a Mon Sep 17 00:00:00 2001 From: arkon Date: Sun, 27 Sep 2020 18:13:20 -0400 Subject: [PATCH] Use tristate checkboxes for chapters list filters --- .../java/eu/kanade/tachiyomi/Migrations.kt | 4 +- .../data/preference/PreferencesHelper.kt | 6 +- .../tachiyomi/ui/library/LibraryPresenter.kt | 15 ++- .../ui/library/LibrarySettingsSheet.kt | 14 ++- .../tachiyomi/ui/manga/MangaPresenter.kt | 99 ++++++++++++------- .../ui/manga/chapter/ChaptersSettingsSheet.kt | 42 ++++---- .../widget/ExtendedNavigationView.kt | 14 +-- app/src/main/res/values/strings.xml | 1 - 8 files changed, 111 insertions(+), 84 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index 204ca4edf..8182dc71f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -98,8 +98,8 @@ object Migrations { val prefs = PreferenceManager.getDefaultSharedPreferences(context) fun convertBooleanPrefToTriState(key: String): Int { val oldPrefValue = prefs.getBoolean(key, false) - return if (oldPrefValue) ExtendedNavigationView.Item.TriStateGroup.STATE_INCLUDE - else ExtendedNavigationView.Item.TriStateGroup.STATE_IGNORE + return if (oldPrefValue) ExtendedNavigationView.Item.TriStateGroup.State.INCLUDE.value + else ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value } prefs.edit { putInt(PreferenceKeys.filterDownloaded, convertBooleanPrefToTriState("pref_filter_downloaded_key")) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 86e1733aa..0daa433d7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -213,11 +213,11 @@ class PreferencesHelper(val context: Context) { fun categoryTabs() = flowPrefs.getBoolean(Keys.categoryTabs, true) - fun filterDownloaded() = flowPrefs.getInt(Keys.filterDownloaded, ExtendedNavigationView.Item.TriStateGroup.STATE_IGNORE) + fun filterDownloaded() = flowPrefs.getInt(Keys.filterDownloaded, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) - fun filterUnread() = flowPrefs.getInt(Keys.filterUnread, ExtendedNavigationView.Item.TriStateGroup.STATE_IGNORE) + fun filterUnread() = flowPrefs.getInt(Keys.filterUnread, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) - fun filterCompleted() = flowPrefs.getInt(Keys.filterCompleted, ExtendedNavigationView.Item.TriStateGroup.STATE_IGNORE) + fun filterCompleted() = flowPrefs.getInt(Keys.filterCompleted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun librarySortingMode() = flowPrefs.getInt(Keys.librarySortingMode, 0) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 7c99e69c9..2bb7658b1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -19,8 +19,7 @@ import eu.kanade.tachiyomi.util.lang.combineLatest import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.removeCovers -import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_IGNORE -import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_INCLUDE +import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State import rx.Observable import rx.Subscription import rx.android.schedulers.AndroidSchedulers @@ -118,30 +117,30 @@ class LibraryPresenter( val filterCompleted = preferences.filterCompleted().get() val filterFnUnread: (LibraryItem) -> Boolean = unread@{ item -> - if (filterUnread == STATE_IGNORE) return@unread true + if (filterUnread == State.IGNORE.value) return@unread true val isUnread = item.manga.unread != 0 - return@unread if (filterUnread == STATE_INCLUDE) isUnread + return@unread if (filterUnread == State.INCLUDE.value) isUnread else !isUnread } val filterFnCompleted: (LibraryItem) -> Boolean = completed@{ item -> - if (filterCompleted == STATE_IGNORE) return@completed true + if (filterCompleted == State.IGNORE.value) return@completed true val isCompleted = item.manga.status == SManga.COMPLETED - return@completed if (filterCompleted == STATE_INCLUDE) isCompleted + return@completed if (filterCompleted == State.INCLUDE.value) isCompleted else !isCompleted } val filterFnDownloaded: (LibraryItem) -> Boolean = downloaded@{ item -> - if (!downloadedOnly && filterDownloaded == STATE_IGNORE) return@downloaded true + if (!downloadedOnly && filterDownloaded == State.IGNORE.value) return@downloaded true val isDownloaded = when { item.manga.isLocal() -> true item.downloadCount != -1 -> item.downloadCount > 0 else -> downloadManager.getDownloadCount(item.manga) > 0 } - return@downloaded if (downloadedOnly || filterDownloaded == STATE_INCLUDE) isDownloaded + return@downloaded if (downloadedOnly || filterDownloaded == State.INCLUDE.value) isDownloaded else !isDownloaded } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt index 4ea2a9a37..a9d92e571 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt @@ -8,9 +8,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.widget.ExtendedNavigationView -import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_EXCLUDE -import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_IGNORE -import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.Companion.STATE_INCLUDE +import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog import uy.kohesive.injekt.injectLazy @@ -62,7 +60,7 @@ class LibrarySettingsSheet( * Returns true if there's at least one filter from [FilterGroup] active. */ fun hasActiveFilters(): Boolean { - return filterGroup.items.any { it.state != STATE_IGNORE } + return filterGroup.items.any { it.state != State.IGNORE.value } } inner class FilterGroup : Group { @@ -77,7 +75,7 @@ class LibrarySettingsSheet( override fun initModels() { if (preferences.downloadedOnly().get()) { - downloaded.state = STATE_INCLUDE + downloaded.state = State.INCLUDE.value downloaded.enabled = false } else { downloaded.state = preferences.filterDownloaded().get() @@ -89,9 +87,9 @@ class LibrarySettingsSheet( override fun onItemClicked(item: Item) { item as Item.TriStateGroup val newState = when (item.state) { - STATE_IGNORE -> STATE_INCLUDE - STATE_INCLUDE -> STATE_EXCLUDE - STATE_EXCLUDE -> STATE_IGNORE + State.IGNORE.value -> State.INCLUDE.value + State.INCLUDE.value -> State.EXCLUDE.value + State.EXCLUDE.value -> State.IGNORE.value else -> throw Exception("Unknown State") } item.state = newState diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 24002f7fe..32ea0ad0e 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.util.prepUpdateCover import eu.kanade.tachiyomi.util.removeCovers import eu.kanade.tachiyomi.util.shouldDownloadNewChapters import eu.kanade.tachiyomi.util.updateCoverLastModified +import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State import rx.Observable import rx.Subscription import rx.android.schedulers.AndroidSchedulers @@ -368,17 +369,28 @@ class MangaPresenter( */ private fun applyChapterFilters(chapters: List): Observable> { var observable = Observable.from(chapters).subscribeOn(Schedulers.io()) - if (onlyUnread()) { + + val unreadFilter = onlyUnread() + if (unreadFilter == State.INCLUDE) { observable = observable.filter { !it.read } - } else if (onlyRead()) { + } else if (unreadFilter == State.EXCLUDE) { observable = observable.filter { it.read } } - if (onlyDownloaded()) { + + val downloadedFilter = onlyDownloaded() + if (downloadedFilter == State.INCLUDE) { observable = observable.filter { it.isDownloaded || it.manga.isLocal() } + } else if (downloadedFilter == State.EXCLUDE) { + observable = observable.filter { !it.isDownloaded && !it.manga.isLocal() } } - if (onlyBookmarked()) { + + val bookmarkedFilter = onlyBookmarked() + if (bookmarkedFilter == State.INCLUDE) { observable = observable.filter { it.bookmark } + } else if (bookmarkedFilter == State.EXCLUDE) { + observable = observable.filter { !it.bookmark } } + val sortFunction: (Chapter, Chapter) -> Int = when (manga.sorting) { Manga.SORTING_SOURCE -> when (sortDescending()) { true -> { c1, c2 -> c1.source_order.compareTo(c2.source_order) } @@ -394,6 +406,7 @@ class MangaPresenter( } else -> throw NotImplementedError("Unimplemented sorting method") } + return observable.toSortedList(sortFunction) } @@ -412,7 +425,7 @@ class MangaPresenter( } // Force UI update if downloaded filter active and download finished. - if (onlyDownloaded() && download.status == Download.DOWNLOADED) { + if (onlyDownloaded() != State.IGNORE && download.status == Download.DOWNLOADED) { refreshChapters() } } @@ -477,7 +490,7 @@ class MangaPresenter( fun deleteChapters(chapters: List) { Observable.just(chapters) .doOnNext { deleteChaptersInternal(chapters) } - .doOnNext { if (onlyDownloaded()) refreshChapters() } + .doOnNext { if (onlyDownloaded() != State.IGNORE) refreshChapters() } .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribeFirst( @@ -518,40 +531,42 @@ class MangaPresenter( /** * Sets the read filter and requests an UI update. - * @param onlyUnread whether to display only unread chapters or all chapters. + * @param state whether to display only unread chapters or all chapters. */ - fun setUnreadFilter(onlyUnread: Boolean) { - manga.readFilter = if (onlyUnread) Manga.SHOW_UNREAD else Manga.SHOW_ALL - db.updateFlags(manga).executeAsBlocking() - refreshChapters() - } - - /** - * Sets the read filter and requests an UI update. - * @param onlyRead whether to display only read chapters or all chapters. - */ - fun setReadFilter(onlyRead: Boolean) { - manga.readFilter = if (onlyRead) Manga.SHOW_READ else Manga.SHOW_ALL + fun setUnreadFilter(state: State) { + manga.readFilter = when (state) { + State.IGNORE -> Manga.SHOW_ALL + State.INCLUDE -> Manga.SHOW_UNREAD + State.EXCLUDE -> Manga.SHOW_READ + } db.updateFlags(manga).executeAsBlocking() refreshChapters() } /** * Sets the download filter and requests an UI update. - * @param onlyDownloaded whether to display only downloaded chapters or all chapters. + * @param state whether to display only downloaded chapters or all chapters. */ - fun setDownloadedFilter(onlyDownloaded: Boolean) { - manga.downloadedFilter = if (onlyDownloaded) Manga.SHOW_DOWNLOADED else Manga.SHOW_ALL + fun setDownloadedFilter(state: State) { + manga.downloadedFilter = when (state) { + State.IGNORE -> Manga.SHOW_ALL + State.INCLUDE -> Manga.SHOW_DOWNLOADED + State.EXCLUDE -> Manga.SHOW_NOT_DOWNLOADED + } db.updateFlags(manga).executeAsBlocking() refreshChapters() } /** * Sets the bookmark filter and requests an UI update. - * @param onlyBookmarked whether to display only bookmarked chapters or all chapters. + * @param state whether to display only bookmarked chapters or all chapters. */ - fun setBookmarkedFilter(onlyBookmarked: Boolean) { - manga.bookmarkedFilter = if (onlyBookmarked) Manga.SHOW_BOOKMARKED else Manga.SHOW_ALL + fun setBookmarkedFilter(state: State) { + manga.bookmarkedFilter = when (state) { + State.IGNORE -> Manga.SHOW_ALL + State.INCLUDE -> Manga.SHOW_BOOKMARKED + State.EXCLUDE -> Manga.SHOW_NOT_BOOKMARKED + } db.updateFlags(manga).executeAsBlocking() refreshChapters() } @@ -585,29 +600,37 @@ class MangaPresenter( /** * Whether the display only downloaded filter is enabled. */ - fun onlyDownloaded(): Boolean { - return forceDownloaded() || manga.downloadedFilter == Manga.SHOW_DOWNLOADED + fun onlyDownloaded(): State { + if (forceDownloaded()) { + return State.INCLUDE + } + return when (manga.downloadedFilter) { + Manga.SHOW_DOWNLOADED -> State.INCLUDE + Manga.SHOW_NOT_DOWNLOADED -> State.EXCLUDE + else -> State.IGNORE + } } /** * Whether the display only downloaded filter is enabled. */ - fun onlyBookmarked(): Boolean { - return manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED + fun onlyBookmarked(): State { + return when (manga.bookmarkedFilter) { + Manga.SHOW_BOOKMARKED -> State.INCLUDE + Manga.SHOW_NOT_BOOKMARKED -> State.EXCLUDE + else -> State.IGNORE + } } /** * Whether the display only unread filter is enabled. */ - fun onlyUnread(): Boolean { - return manga.readFilter == Manga.SHOW_UNREAD - } - - /** - * Whether the display only read filter is enabled. - */ - fun onlyRead(): Boolean { - return manga.readFilter == Manga.SHOW_READ + fun onlyUnread(): State { + return when (manga.readFilter) { + Manga.SHOW_UNREAD -> State.INCLUDE + Manga.SHOW_READ -> State.EXCLUDE + else -> State.IGNORE + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt index 321369039..e79b47dd0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt @@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.ui.manga.MangaPresenter import eu.kanade.tachiyomi.util.view.popupMenu import eu.kanade.tachiyomi.widget.ExtendedNavigationView +import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog class ChaptersSettingsSheet( @@ -81,36 +82,43 @@ class ChaptersSettingsSheet( * Returns true if there's at least one filter from [FilterGroup] active. */ fun hasActiveFilters(): Boolean { - return filterGroup.items.any { it.checked } + return filterGroup.items.any { it.state != State.IGNORE.value } } inner class FilterGroup : Group { - private val read = Item.CheckboxGroup(R.string.action_filter_read, this) - private val unread = Item.CheckboxGroup(R.string.action_filter_unread, this) - private val downloaded = Item.CheckboxGroup(R.string.action_filter_downloaded, this) - private val bookmarked = Item.CheckboxGroup(R.string.action_filter_bookmarked, this) + private val unread = Item.TriStateGroup(R.string.action_filter_unread, this) + private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this) + private val bookmarked = Item.TriStateGroup(R.string.action_filter_bookmarked, this) override val header = null - override val items = listOf(read, unread, downloaded, bookmarked) + override val items = listOf(unread, downloaded, bookmarked) override val footer = null override fun initModels() { - read.checked = presenter.onlyRead() - unread.checked = presenter.onlyUnread() - downloaded.checked = presenter.onlyDownloaded() - downloaded.enabled = !presenter.forceDownloaded() - bookmarked.checked = presenter.onlyBookmarked() + if (presenter.forceDownloaded()) { + downloaded.state = State.INCLUDE.value + downloaded.enabled = false + } else { + downloaded.state = presenter.onlyDownloaded().value + } + unread.state = presenter.onlyUnread().value + bookmarked.state = presenter.onlyBookmarked().value } override fun onItemClicked(item: Item) { - item as Item.CheckboxGroup - item.checked = !item.checked + item as Item.TriStateGroup + val newState = when (item.state) { + State.IGNORE.value -> State.INCLUDE + State.INCLUDE.value -> State.EXCLUDE + State.EXCLUDE.value -> State.IGNORE + else -> throw Exception("Unknown State") + } + item.state = newState.value when (item) { - read -> presenter.setReadFilter(item.checked) - unread -> presenter.setUnreadFilter(item.checked) - downloaded -> presenter.setDownloadedFilter(item.checked) - bookmarked -> presenter.setBookmarkedFilter(item.checked) + downloaded -> presenter.setDownloadedFilter(newState) + unread -> presenter.setUnreadFilter(newState) + bookmarked -> presenter.setBookmarkedFilter(newState) } initModels() diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt index be59f618d..b52a49cdb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/ExtendedNavigationView.kt @@ -112,17 +112,17 @@ open class ExtendedNavigationView @JvmOverloads constructor( */ class TriStateGroup(resId: Int, group: Group) : MultiStateGroup(resId, group) { - companion object { - const val STATE_IGNORE = 0 - const val STATE_INCLUDE = 1 - const val STATE_EXCLUDE = 2 + enum class State(val value: Int) { + IGNORE(0), + INCLUDE(1), + EXCLUDE(2) } override fun getStateDrawable(context: Context): Drawable? { return when (state) { - STATE_IGNORE -> tintVector(context, R.drawable.ic_check_box_outline_blank_24dp, R.attr.colorControlNormal) - STATE_INCLUDE -> tintVector(context, R.drawable.ic_check_box_24dp) - STATE_EXCLUDE -> tintVector(context, R.drawable.ic_check_box_x_24dp) + State.IGNORE.value -> tintVector(context, R.drawable.ic_check_box_outline_blank_24dp, R.attr.colorControlNormal) + State.INCLUDE.value -> tintVector(context, R.drawable.ic_check_box_24dp) + State.EXCLUDE.value -> tintVector(context, R.drawable.ic_check_box_x_24dp) else -> throw Exception("Unknown state") } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e06130ad7..948dac401 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,7 +35,6 @@ Downloaded Bookmarked Unread - Read Remove filter Alphabetically Total chapters