mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 06:17:57 +01:00 
			
		
		
		
	Use tristate checkboxes for chapters list filters
This commit is contained in:
		| @@ -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")) | ||||
|   | ||||
| @@ -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) | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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<ChapterItem>): Observable<List<ChapterItem>> { | ||||
|         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<ChapterItem>) { | ||||
|         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 | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -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() | ||||
|   | ||||
| @@ -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") | ||||
|                 } | ||||
|             } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user