Extend track filter (#4344)

* Allow to filter for each tracker logged in

* Simplify filter logic

* Use variable names instead of it

and rename variables

* Change how trackFilters and items are setup

* Use variable name instead of it and try cleanup filterFnTracking

* Changes from feedback
This commit is contained in:
Andreas 2021-01-24 21:24:00 +01:00 committed by GitHub
parent d3c087375b
commit fea2e0a265
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 24 deletions

View File

@ -221,7 +221,7 @@ class PreferencesHelper(val context: Context) {
fun filterCompleted() = flowPrefs.getInt(Keys.filterCompleted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun filterCompleted() = flowPrefs.getInt(Keys.filterCompleted, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun filterTracking() = flowPrefs.getInt(Keys.filterTracking, ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) fun filterTracking(name: String) = flowPrefs.getInt("${Keys.filterTracking}_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value)
fun librarySortingMode() = flowPrefs.getInt(Keys.librarySortingMode, 0) fun librarySortingMode() = flowPrefs.getInt(Keys.librarySortingMode, 0)

View File

@ -112,13 +112,16 @@ class LibraryPresenter(
* *
* @param map the map to filter. * @param map the map to filter.
*/ */
private fun applyFilters(map: LibraryMap, trackMap: Map<Long, Boolean>): LibraryMap { private fun applyFilters(map: LibraryMap, trackMap: Map<Long, Map<Int, Boolean>>): LibraryMap {
val downloadedOnly = preferences.downloadedOnly().get() val downloadedOnly = preferences.downloadedOnly().get()
val filterDownloaded = preferences.filterDownloaded().get() val filterDownloaded = preferences.filterDownloaded().get()
val filterUnread = preferences.filterUnread().get() val filterUnread = preferences.filterUnread().get()
val filterCompleted = preferences.filterCompleted().get() val filterCompleted = preferences.filterCompleted().get()
val tracking = preferences.filterTracking().get() val loggedInServices = trackManager.services.filter { trackService -> trackService.isLogged }
val isNotLogged = !trackManager.hasLoggedServices() .associate { trackService ->
Pair(trackService.id, preferences.filterTracking(trackService.name).get())
}
val isNotAnyLoggedIn = !loggedInServices.values.any()
val filterFnUnread: (LibraryItem) -> Boolean = unread@{ item -> val filterFnUnread: (LibraryItem) -> Boolean = unread@{ item ->
if (filterUnread == State.IGNORE.value) return@unread true if (filterUnread == State.IGNORE.value) return@unread true
@ -149,11 +152,27 @@ class LibraryPresenter(
} }
val filterFnTracking: (LibraryItem) -> Boolean = tracking@{ item -> val filterFnTracking: (LibraryItem) -> Boolean = tracking@{ item ->
if (isNotLogged || tracking == State.IGNORE.value) return@tracking true if (isNotAnyLoggedIn) return@tracking true
val isTracking = trackMap[item.manga.id ?: -1] ?: false val trackedManga = trackMap[item.manga.id ?: -1]
return@tracking if (tracking == State.INCLUDE.value) isTracking else !isTracking val containsExclude = loggedInServices.filterValues { it == State.EXCLUDE.value }
val containsInclude = loggedInServices.filterValues { it == State.INCLUDE.value }
if (!containsExclude.any() && !containsInclude.any()) return@tracking true
val exclude = trackedManga?.filterKeys { containsExclude.containsKey(it) }?.values ?: emptyList()
val include = trackedManga?.filterKeys { containsInclude.containsKey(it) }?.values ?: emptyList()
if (containsInclude.any() && containsExclude.any()) {
return@tracking if (exclude.isNotEmpty()) !exclude.any() else include.any()
}
if (containsExclude.any()) return@tracking !exclude.any()
if (containsInclude.any()) return@tracking include.any()
return@tracking false
} }
val filterFn: (LibraryItem) -> Boolean = filter@{ item -> val filterFn: (LibraryItem) -> Boolean = filter@{ item ->
@ -300,7 +319,7 @@ class LibraryPresenter(
* *
* @return an observable of tracked manga. * @return an observable of tracked manga.
*/ */
private fun getFilterObservable(): Observable<Map<Long, Boolean>> { private fun getFilterObservable(): Observable<Map<Long, Map<Int, Boolean>>> {
return getTracksObservable().combineLatest(filterTriggerRelay.observeOn(Schedulers.io())) { tracks, _ -> tracks } return getTracksObservable().combineLatest(filterTriggerRelay.observeOn(Schedulers.io())) { tracks, _ -> tracks }
} }
@ -309,13 +328,13 @@ class LibraryPresenter(
* *
* @return an observable of tracked manga. * @return an observable of tracked manga.
*/ */
private fun getTracksObservable(): Observable<Map<Long, Boolean>> { private fun getTracksObservable(): Observable<Map<Long, Map<Int, Boolean>>> {
return db.getTracks().asRxObservable().map { tracks -> return db.getTracks().asRxObservable().map { tracks ->
tracks.groupBy { it.manga_id } tracks.groupBy { it.manga_id }
.mapValues { tracksForMangaId -> .mapValues { tracksForMangaId ->
// Check if any of the trackers is logged in for the current manga id // Check if any of the trackers is logged in for the current manga id
tracksForMangaId.value.any { tracksForMangaId.value.associate {
trackManager.getService(it.sync_id)?.isLogged ?: false Pair(it.sync_id, trackManager.getService(it.sync_id)?.isLogged ?: false)
} }
} }
}.observeOn(Schedulers.io()) }.observeOn(Schedulers.io())

View File

@ -8,14 +8,22 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.anilist.Anilist
import eu.kanade.tachiyomi.data.track.bangumi.Bangumi
import eu.kanade.tachiyomi.data.track.kitsu.Kitsu
import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeList
import eu.kanade.tachiyomi.data.track.shikimori.Shikimori
import eu.kanade.tachiyomi.widget.ExtendedNavigationView import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import uy.kohesive.injekt.injectValue
class LibrarySettingsSheet( class LibrarySettingsSheet(
router: Router, router: Router,
private val trackManager: TrackManager = Injekt.get(),
onGroupClickListener: (ExtendedNavigationView.Group) -> Unit onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
) : TabbedBottomSheetDialog(router) { ) : TabbedBottomSheetDialog(router) {
@ -54,8 +62,6 @@ class LibrarySettingsSheet(
private val filterGroup = FilterGroup() private val filterGroup = FilterGroup()
private val trackManager: TrackManager by injectValue()
init { init {
setGroups(listOf(filterGroup)) setGroups(listOf(filterGroup))
} }
@ -64,7 +70,7 @@ class LibrarySettingsSheet(
* Returns true if there's at least one filter from [FilterGroup] active. * Returns true if there's at least one filter from [FilterGroup] active.
*/ */
fun hasActiveFilters(): Boolean { fun hasActiveFilters(): Boolean {
return filterGroup.items.any { it.state != State.IGNORE.value } return filterGroup.items.filterIsInstance<Item.TriStateGroup>().any { it.state != State.IGNORE.value }
} }
inner class FilterGroup : Group { inner class FilterGroup : Group {
@ -72,12 +78,41 @@ class LibrarySettingsSheet(
private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this) private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this)
private val unread = Item.TriStateGroup(R.string.action_filter_unread, this) private val unread = Item.TriStateGroup(R.string.action_filter_unread, this)
private val completed = Item.TriStateGroup(R.string.completed, this) private val completed = Item.TriStateGroup(R.string.completed, this)
private val tracking = Item.TriStateGroup(R.string.action_filter_tracked, this) private val trackFilters: Map<String, Item.TriStateGroup>
override val header = null override val header = null
override val items = listOf(downloaded, unread, completed, tracking) override val items: List<Item>
override val footer = null override val footer = null
init {
trackManager.services.filter { service -> service.isLogged }
.also { services ->
val size = services.size
trackFilters = services.associate { service ->
Pair(service.name, Item.TriStateGroup(getServiceResId(service, size), this))
}
val list: MutableList<Item> = mutableListOf(downloaded, unread, completed)
if (size > 1) list.add(Item.Header(R.string.action_filter_tracked))
list.addAll(trackFilters.values)
items = list
}
}
private fun getServiceResId(service: TrackService, size: Int): Int {
return if (size > 1) getServiceResId(service) else R.string.action_filter_tracked
}
private fun getServiceResId(service: TrackService): Int {
return when (service) {
is Anilist -> R.string.anilist
is MyAnimeList -> R.string.my_anime_list
is Kitsu -> R.string.kitsu
is Bangumi -> R.string.bangumi
is Shikimori -> R.string.shikimori
else -> R.string.unknown
}
}
override fun initModels() { override fun initModels() {
if (preferences.downloadedOnly().get()) { if (preferences.downloadedOnly().get()) {
downloaded.state = State.INCLUDE.value downloaded.state = State.INCLUDE.value
@ -88,12 +123,8 @@ class LibrarySettingsSheet(
unread.state = preferences.filterUnread().get() unread.state = preferences.filterUnread().get()
completed.state = preferences.filterCompleted().get() completed.state = preferences.filterCompleted().get()
if (!trackManager.hasLoggedServices()) { trackFilters.forEach { trackFilter ->
tracking.state = State.IGNORE.value trackFilter.value.state = preferences.filterTracking(trackFilter.key).get()
tracking.isVisible = false
} else {
tracking.state = preferences.filterTracking().get()
tracking.isVisible = true
} }
} }
@ -110,7 +141,13 @@ class LibrarySettingsSheet(
downloaded -> preferences.filterDownloaded().set(newState) downloaded -> preferences.filterDownloaded().set(newState)
unread -> preferences.filterUnread().set(newState) unread -> preferences.filterUnread().set(newState)
completed -> preferences.filterCompleted().set(newState) completed -> preferences.filterCompleted().set(newState)
tracking -> preferences.filterTracking().set(newState) else -> {
trackFilters.forEach { trackFilter ->
if (trackFilter.value == item) {
preferences.filterTracking(trackFilter.key).set(newState)
}
}
}
} }
adapter.notifyItemChanged(item) adapter.notifyItemChanged(item)

View File

@ -747,4 +747,11 @@
<string name="spen_previous_page">Previous page</string> <string name="spen_previous_page">Previous page</string>
<string name="spen_next_page">Next page</string> <string name="spen_next_page">Next page</string>
<!-- Tracker names -->
<string name="anilist" translatable="false">AniList</string>
<string name="my_anime_list" translatable="false">MyAnimeList</string>
<string name="kitsu" translatable="false">Kitsu</string>
<string name="bangumi" translatable="false">Bangumi</string>
<string name="shikimori" translatable="false">Shikimori</string>
</resources> </resources>