mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	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:
		@@ -221,7 +221,7 @@ class PreferencesHelper(val context: Context) {
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -112,13 +112,16 @@ class LibraryPresenter(
 | 
			
		||||
     *
 | 
			
		||||
     * @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 filterDownloaded = preferences.filterDownloaded().get()
 | 
			
		||||
        val filterUnread = preferences.filterUnread().get()
 | 
			
		||||
        val filterCompleted = preferences.filterCompleted().get()
 | 
			
		||||
        val tracking = preferences.filterTracking().get()
 | 
			
		||||
        val isNotLogged = !trackManager.hasLoggedServices()
 | 
			
		||||
        val loggedInServices = trackManager.services.filter { trackService -> trackService.isLogged }
 | 
			
		||||
            .associate { trackService ->
 | 
			
		||||
                Pair(trackService.id, preferences.filterTracking(trackService.name).get())
 | 
			
		||||
            }
 | 
			
		||||
        val isNotAnyLoggedIn = !loggedInServices.values.any()
 | 
			
		||||
 | 
			
		||||
        val filterFnUnread: (LibraryItem) -> Boolean = unread@{ item ->
 | 
			
		||||
            if (filterUnread == State.IGNORE.value) return@unread true
 | 
			
		||||
@@ -149,11 +152,27 @@ class LibraryPresenter(
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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 ->
 | 
			
		||||
@@ -300,7 +319,7 @@ class LibraryPresenter(
 | 
			
		||||
     *
 | 
			
		||||
     * @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 }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -309,13 +328,13 @@ class LibraryPresenter(
 | 
			
		||||
     *
 | 
			
		||||
     * @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 ->
 | 
			
		||||
            tracks.groupBy { it.manga_id }
 | 
			
		||||
                .mapValues { tracksForMangaId ->
 | 
			
		||||
                    // Check if any of the trackers is logged in for the current manga id
 | 
			
		||||
                    tracksForMangaId.value.any {
 | 
			
		||||
                        trackManager.getService(it.sync_id)?.isLogged ?: false
 | 
			
		||||
                    tracksForMangaId.value.associate {
 | 
			
		||||
                        Pair(it.sync_id, trackManager.getService(it.sync_id)?.isLogged ?: false)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
        }.observeOn(Schedulers.io())
 | 
			
		||||
 
 | 
			
		||||
@@ -8,14 +8,22 @@ import eu.kanade.tachiyomi.R
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
 | 
			
		||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 | 
			
		||||
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.Item.TriStateGroup.State
 | 
			
		||||
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.injectValue
 | 
			
		||||
 | 
			
		||||
class LibrarySettingsSheet(
 | 
			
		||||
    router: Router,
 | 
			
		||||
    private val trackManager: TrackManager = Injekt.get(),
 | 
			
		||||
    onGroupClickListener: (ExtendedNavigationView.Group) -> Unit
 | 
			
		||||
) : TabbedBottomSheetDialog(router) {
 | 
			
		||||
 | 
			
		||||
@@ -54,8 +62,6 @@ class LibrarySettingsSheet(
 | 
			
		||||
 | 
			
		||||
        private val filterGroup = FilterGroup()
 | 
			
		||||
 | 
			
		||||
        private val trackManager: TrackManager by injectValue()
 | 
			
		||||
 | 
			
		||||
        init {
 | 
			
		||||
            setGroups(listOf(filterGroup))
 | 
			
		||||
        }
 | 
			
		||||
@@ -64,7 +70,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.value }
 | 
			
		||||
            return filterGroup.items.filterIsInstance<Item.TriStateGroup>().any { it.state != State.IGNORE.value }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        inner class FilterGroup : Group {
 | 
			
		||||
@@ -72,12 +78,41 @@ class LibrarySettingsSheet(
 | 
			
		||||
            private val downloaded = Item.TriStateGroup(R.string.action_filter_downloaded, this)
 | 
			
		||||
            private val unread = Item.TriStateGroup(R.string.action_filter_unread, 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 items = listOf(downloaded, unread, completed, tracking)
 | 
			
		||||
            override val items: List<Item>
 | 
			
		||||
            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() {
 | 
			
		||||
                if (preferences.downloadedOnly().get()) {
 | 
			
		||||
                    downloaded.state = State.INCLUDE.value
 | 
			
		||||
@@ -88,12 +123,8 @@ class LibrarySettingsSheet(
 | 
			
		||||
                unread.state = preferences.filterUnread().get()
 | 
			
		||||
                completed.state = preferences.filterCompleted().get()
 | 
			
		||||
 | 
			
		||||
                if (!trackManager.hasLoggedServices()) {
 | 
			
		||||
                    tracking.state = State.IGNORE.value
 | 
			
		||||
                    tracking.isVisible = false
 | 
			
		||||
                } else {
 | 
			
		||||
                    tracking.state = preferences.filterTracking().get()
 | 
			
		||||
                    tracking.isVisible = true
 | 
			
		||||
                trackFilters.forEach { trackFilter ->
 | 
			
		||||
                    trackFilter.value.state = preferences.filterTracking(trackFilter.key).get()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -110,7 +141,13 @@ class LibrarySettingsSheet(
 | 
			
		||||
                    downloaded -> preferences.filterDownloaded().set(newState)
 | 
			
		||||
                    unread -> preferences.filterUnread().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)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user