Cleanup Library presenter (#8284)
* yeet observable + minor cleanup * move [getTracksFlow] to domain * Lint * Review changes Co-Authored-By: Andreas <6576096+ghostbear@users.noreply.github.com> * Review Changes 2 * Stuff * Rename + Rebase * Lint Co-authored-by: Andreas <6576096+ghostbear@users.noreply.github.com> (cherry picked from commit e36d31bf0fff9652652319fa8b4fc700edc1442a) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt
This commit is contained in:
parent
0d7cff1f43
commit
37207ed58b
@ -63,6 +63,7 @@ import eu.kanade.domain.source.repository.SourceDataRepository
|
|||||||
import eu.kanade.domain.source.repository.SourceRepository
|
import eu.kanade.domain.source.repository.SourceRepository
|
||||||
import eu.kanade.domain.track.interactor.DeleteTrack
|
import eu.kanade.domain.track.interactor.DeleteTrack
|
||||||
import eu.kanade.domain.track.interactor.GetTracks
|
import eu.kanade.domain.track.interactor.GetTracks
|
||||||
|
import eu.kanade.domain.track.interactor.GetTracksPerManga
|
||||||
import eu.kanade.domain.track.interactor.InsertTrack
|
import eu.kanade.domain.track.interactor.InsertTrack
|
||||||
import eu.kanade.domain.track.repository.TrackRepository
|
import eu.kanade.domain.track.repository.TrackRepository
|
||||||
import eu.kanade.domain.updates.interactor.GetUpdates
|
import eu.kanade.domain.updates.interactor.GetUpdates
|
||||||
@ -104,6 +105,7 @@ class DomainModule : InjektModule {
|
|||||||
|
|
||||||
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
addSingletonFactory<TrackRepository> { TrackRepositoryImpl(get()) }
|
||||||
addFactory { DeleteTrack(get()) }
|
addFactory { DeleteTrack(get()) }
|
||||||
|
addFactory { GetTracksPerManga(get()) }
|
||||||
addFactory { GetTracks(get()) }
|
addFactory { GetTracks(get()) }
|
||||||
addFactory { InsertTrack(get()) }
|
addFactory { InsertTrack(get()) }
|
||||||
|
|
||||||
|
@ -40,10 +40,6 @@ class GetTracks(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun subscribe(): Flow<List<Track>> {
|
|
||||||
return trackRepository.getTracksAsFlow()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun subscribe(mangaId: Long): Flow<List<Track>> {
|
fun subscribe(mangaId: Long): Flow<List<Track>> {
|
||||||
return trackRepository.getTracksByMangaIdAsFlow(mangaId)
|
return trackRepository.getTracksByMangaIdAsFlow(mangaId)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package eu.kanade.domain.track.interactor
|
||||||
|
|
||||||
|
import eu.kanade.domain.track.repository.TrackRepository
|
||||||
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
|
import exh.md.utils.FollowStatus
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
class GetTracksPerManga(
|
||||||
|
private val trackRepository: TrackRepository,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun subscribe(): Flow<Map<Long, List<Long>>> {
|
||||||
|
return trackRepository.getTracksAsFlow().map { tracks ->
|
||||||
|
tracks
|
||||||
|
.groupBy { it.mangaId }
|
||||||
|
.mapValues { entry ->
|
||||||
|
entry.value
|
||||||
|
// SY -->
|
||||||
|
.filterNot { it.syncId == TrackManager.MDLIST && it.status == FollowStatus.UNFOLLOWED.int.toLong() }
|
||||||
|
// SY <--
|
||||||
|
.map { it.syncId }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -32,6 +32,7 @@ import eu.kanade.tachiyomi.ui.main.MainActivity
|
|||||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||||
|
import eu.kanade.tachiyomi.util.lang.launchUI
|
||||||
import eu.kanade.tachiyomi.util.system.toast
|
import eu.kanade.tachiyomi.util.system.toast
|
||||||
import exh.favorites.FavoritesIntroDialog
|
import exh.favorites.FavoritesIntroDialog
|
||||||
import exh.favorites.FavoritesSyncStatus
|
import exh.favorites.FavoritesSyncStatus
|
||||||
@ -209,9 +210,8 @@ class LibraryController(
|
|||||||
settingsSheet = LibrarySettingsSheet(router) { group ->
|
settingsSheet = LibrarySettingsSheet(router) { group ->
|
||||||
when (group) {
|
when (group) {
|
||||||
is LibrarySettingsSheet.Filter.FilterGroup -> onFilterChanged()
|
is LibrarySettingsSheet.Filter.FilterGroup -> onFilterChanged()
|
||||||
is LibrarySettingsSheet.Sort.SortGroup -> onSortChanged()
|
|
||||||
// SY -->
|
// SY -->
|
||||||
is LibrarySettingsSheet.Grouping.InternalGroup -> onGroupSettingChanged()
|
is LibrarySettingsSheet.Grouping.InternalGroup -> onGroupChanged()
|
||||||
// SY <--
|
// SY <--
|
||||||
else -> {} // Handled via different mechanisms
|
else -> {} // Handled via different mechanisms
|
||||||
}
|
}
|
||||||
@ -238,20 +238,20 @@ class LibraryController(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onFilterChanged() {
|
private fun onFilterChanged() {
|
||||||
presenter.requestFilterUpdate()
|
viewScope.launchUI {
|
||||||
activity?.invalidateOptionsMenu()
|
presenter.requestFilterUpdate()
|
||||||
|
activity?.invalidateOptionsMenu()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
private fun onGroupSettingChanged() {
|
private fun onGroupChanged() {
|
||||||
presenter.requestGroupsUpdate()
|
viewScope.launchUI {
|
||||||
|
presenter.requestGroupUpdate()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
private fun onSortChanged() {
|
|
||||||
presenter.requestSortUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun search(query: String) {
|
fun search(query: String) {
|
||||||
presenter.searchQuery = query
|
presenter.searchQuery = query
|
||||||
}
|
}
|
||||||
@ -272,7 +272,7 @@ class LibraryController(
|
|||||||
* Clear all of the manga currently selected, and
|
* Clear all of the manga currently selected, and
|
||||||
* invalidate the action mode to revert the top toolbar
|
* invalidate the action mode to revert the top toolbar
|
||||||
*/
|
*/
|
||||||
fun clearSelection() {
|
private fun clearSelection() {
|
||||||
presenter.clearSelection()
|
presenter.clearSelection()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,11 +13,8 @@ import androidx.compose.ui.platform.LocalContext
|
|||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.util.fastAny
|
import androidx.compose.ui.util.fastAny
|
||||||
import androidx.compose.ui.util.fastMap
|
import androidx.compose.ui.util.fastMap
|
||||||
import com.jakewharton.rxrelay.BehaviorRelay
|
|
||||||
import eu.kanade.core.prefs.CheckboxState
|
import eu.kanade.core.prefs.CheckboxState
|
||||||
import eu.kanade.core.prefs.PreferenceMutableState
|
import eu.kanade.core.prefs.PreferenceMutableState
|
||||||
import eu.kanade.core.util.asFlow
|
|
||||||
import eu.kanade.core.util.asObservable
|
|
||||||
import eu.kanade.domain.UnsortedPreferences
|
import eu.kanade.domain.UnsortedPreferences
|
||||||
import eu.kanade.domain.base.BasePreferences
|
import eu.kanade.domain.base.BasePreferences
|
||||||
import eu.kanade.domain.category.interactor.GetCategories
|
import eu.kanade.domain.category.interactor.GetCategories
|
||||||
@ -46,6 +43,7 @@ import eu.kanade.domain.manga.model.MangaUpdate
|
|||||||
import eu.kanade.domain.manga.model.isLocal
|
import eu.kanade.domain.manga.model.isLocal
|
||||||
import eu.kanade.domain.source.service.SourcePreferences
|
import eu.kanade.domain.source.service.SourcePreferences
|
||||||
import eu.kanade.domain.track.interactor.GetTracks
|
import eu.kanade.domain.track.interactor.GetTracks
|
||||||
|
import eu.kanade.domain.track.interactor.GetTracksPerManga
|
||||||
import eu.kanade.domain.track.model.Track
|
import eu.kanade.domain.track.model.Track
|
||||||
import eu.kanade.presentation.category.visualName
|
import eu.kanade.presentation.category.visualName
|
||||||
import eu.kanade.presentation.library.LibraryState
|
import eu.kanade.presentation.library.LibraryState
|
||||||
@ -89,6 +87,7 @@ import exh.util.isLewd
|
|||||||
import exh.util.nullIfBlank
|
import exh.util.nullIfBlank
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.asFlow
|
import kotlinx.coroutines.flow.asFlow
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
@ -96,12 +95,10 @@ import kotlinx.coroutines.flow.combine
|
|||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.onStart
|
||||||
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.flow.toList
|
import kotlinx.coroutines.flow.toList
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import rx.Observable
|
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
|
||||||
import rx.schedulers.Schedulers
|
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.text.Collator
|
import java.text.Collator
|
||||||
@ -122,7 +119,7 @@ typealias LibraryMap = Map<Long, List<LibraryItem>>
|
|||||||
class LibraryPresenter(
|
class LibraryPresenter(
|
||||||
private val state: LibraryStateImpl = LibraryState() as LibraryStateImpl,
|
private val state: LibraryStateImpl = LibraryState() as LibraryStateImpl,
|
||||||
private val getLibraryManga: GetLibraryManga = Injekt.get(),
|
private val getLibraryManga: GetLibraryManga = Injekt.get(),
|
||||||
private val getTracks: GetTracks = Injekt.get(),
|
private val getTracksPerManga: GetTracksPerManga = Injekt.get(),
|
||||||
private val getCategories: GetCategories = Injekt.get(),
|
private val getCategories: GetCategories = Injekt.get(),
|
||||||
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
private val getChapterByMangaId: GetChapterByMangaId = Injekt.get(),
|
||||||
private val setReadStatus: SetReadStatus = Injekt.get(),
|
private val setReadStatus: SetReadStatus = Injekt.get(),
|
||||||
@ -139,6 +136,7 @@ class LibraryPresenter(
|
|||||||
private val unsortedPreferences: UnsortedPreferences = Injekt.get(),
|
private val unsortedPreferences: UnsortedPreferences = Injekt.get(),
|
||||||
private val sourcePreferences: SourcePreferences = Injekt.get(),
|
private val sourcePreferences: SourcePreferences = Injekt.get(),
|
||||||
private val searchEngine: SearchEngine = SearchEngine(),
|
private val searchEngine: SearchEngine = SearchEngine(),
|
||||||
|
private val getTracks: GetTracks = Injekt.get(),
|
||||||
private val customMangaManager: CustomMangaManager = Injekt.get(),
|
private val customMangaManager: CustomMangaManager = Injekt.get(),
|
||||||
private val getMergedMangaById: GetMergedMangaById = Injekt.get(),
|
private val getMergedMangaById: GetMergedMangaById = Injekt.get(),
|
||||||
private val getMergedChaptersByMangaId: GetMergedChapterByMangaId = Injekt.get(),
|
private val getMergedChaptersByMangaId: GetMergedChapterByMangaId = Injekt.get(),
|
||||||
@ -169,15 +167,13 @@ class LibraryPresenter(
|
|||||||
val isDownloadOnly: Boolean by preferences.downloadedOnly().asState()
|
val isDownloadOnly: Boolean by preferences.downloadedOnly().asState()
|
||||||
val isIncognitoMode: Boolean by preferences.incognitoMode().asState()
|
val isIncognitoMode: Boolean by preferences.incognitoMode().asState()
|
||||||
|
|
||||||
/**
|
private val _filterChanges: Channel<Unit> = Channel(Int.MAX_VALUE)
|
||||||
* Relay used to apply the UI filters to the last emission of the library.
|
private val filterChanges = _filterChanges.receiveAsFlow().onStart { emit(Unit) }
|
||||||
*/
|
|
||||||
private val filterTriggerRelay = BehaviorRelay.create(Unit)
|
|
||||||
|
|
||||||
/**
|
// SY -->
|
||||||
* Relay used to apply the selected sorting method to the last emission of the library.
|
private val _groupChanges: Channel<Unit> = Channel(Int.MAX_VALUE)
|
||||||
*/
|
private val groupChanges = _groupChanges.receiveAsFlow().onStart { emit(Unit) }
|
||||||
private val sortTriggerRelay = BehaviorRelay.create(Unit)
|
// SY <--
|
||||||
|
|
||||||
private var librarySubscription: Job? = null
|
private var librarySubscription: Job? = null
|
||||||
|
|
||||||
@ -191,11 +187,6 @@ class LibraryPresenter(
|
|||||||
service.id to preferences.context.getString(service.nameRes())
|
service.id to preferences.context.getString(service.nameRes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Relay used to apply the UI update to the last emission of the library.
|
|
||||||
*/
|
|
||||||
private val groupingTriggerRelay = BehaviorRelay.create(Unit)
|
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
override fun onCreate(savedState: Bundle?) {
|
override fun onCreate(savedState: Bundle?) {
|
||||||
@ -226,28 +217,21 @@ class LibraryPresenter(
|
|||||||
*/
|
*/
|
||||||
if (librarySubscription == null || librarySubscription!!.isCancelled) {
|
if (librarySubscription == null || librarySubscription!!.isCancelled) {
|
||||||
librarySubscription = presenterScope.launchIO {
|
librarySubscription = presenterScope.launchIO {
|
||||||
getLibraryFlow().asObservable()
|
combine(getLibraryFlow(), getTracksPerManga.subscribe(), filterChanges /* SY --> */, groupChanges/* SY <-- */) { library, tracks, _, _ ->
|
||||||
// SY -->
|
library.mangaMap
|
||||||
.combineLatest(groupingTriggerRelay.observeOn(Schedulers.io())) { lib, _ ->
|
.applyFilters(tracks)
|
||||||
val (map, categories) = applyGrouping(lib.mangaMap, lib.categories)
|
.applySort(library.categories)
|
||||||
lib.copy(mangaMap = map, categories = categories)
|
// SY -->
|
||||||
}
|
.applyGrouping(library.categories)
|
||||||
// SY <--
|
// SY <--
|
||||||
.combineLatest(getFilterObservable()) { lib, tracks ->
|
}
|
||||||
lib.copy(mangaMap = applyFilters(lib.mangaMap, tracks))
|
|
||||||
}
|
|
||||||
.combineLatest(sortTriggerRelay.observeOn(Schedulers.io())) { lib, _ ->
|
|
||||||
lib.copy(mangaMap = applySort(lib.categories, lib.mangaMap))
|
|
||||||
}
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.asFlow()
|
|
||||||
.collectLatest {
|
.collectLatest {
|
||||||
// SY -->
|
// SY -->
|
||||||
state.groupType = libraryPreferences.groupLibraryBy().get()
|
state.groupType = libraryPreferences.groupLibraryBy().get()
|
||||||
state.categories = it.categories
|
state.categories = it.categories
|
||||||
// SY <--
|
// SY <--
|
||||||
state.isLoading = false
|
state.isLoading = false
|
||||||
loadedManga = it.mangaMap
|
loadedManga = /* SY --> */ it.mangaMap /* SY <-- */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -255,21 +239,25 @@ class LibraryPresenter(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies library filters to the given map of manga.
|
* Applies library filters to the given map of manga.
|
||||||
*
|
|
||||||
* @param map the map to filter.
|
|
||||||
*/
|
*/
|
||||||
private fun applyFilters(map: LibraryMap, trackMap: Map<Long, Map<Long, Boolean>>): LibraryMap {
|
private fun LibraryMap.applyFilters(trackMap: Map<Long, List<Long>>): LibraryMap {
|
||||||
val downloadedOnly = preferences.downloadedOnly().get()
|
val downloadedOnly = preferences.downloadedOnly().get()
|
||||||
val filterDownloaded = libraryPreferences.filterDownloaded().get()
|
val filterDownloaded = libraryPreferences.filterDownloaded().get()
|
||||||
val filterUnread = libraryPreferences.filterUnread().get()
|
val filterUnread = libraryPreferences.filterUnread().get()
|
||||||
val filterStarted = libraryPreferences.filterStarted().get()
|
val filterStarted = libraryPreferences.filterStarted().get()
|
||||||
val filterBookmarked = libraryPreferences.filterBookmarked().get()
|
val filterBookmarked = libraryPreferences.filterBookmarked().get()
|
||||||
val filterCompleted = libraryPreferences.filterCompleted().get()
|
val filterCompleted = libraryPreferences.filterCompleted().get()
|
||||||
val loggedInServices = trackManager.services.filter { trackService -> trackService.isLogged }
|
|
||||||
|
val loggedInTrackServices = trackManager.services.filter { trackService -> trackService.isLogged }
|
||||||
.associate { trackService ->
|
.associate { trackService ->
|
||||||
Pair(trackService.id, libraryPreferences.filterTracking(trackService.id.toInt()).get())
|
trackService.id to libraryPreferences.filterTracking(trackService.id.toInt()).get()
|
||||||
}
|
}
|
||||||
val isNotAnyLoggedIn = !loggedInServices.values.any()
|
val isNotLoggedInAnyTrack = loggedInTrackServices.isEmpty()
|
||||||
|
|
||||||
|
val excludedTracks = loggedInTrackServices.mapNotNull { if (it.value == State.EXCLUDE.value) it.key else null }
|
||||||
|
val includedTracks = loggedInTrackServices.mapNotNull { if (it.value == State.INCLUDE.value) it.key else null }
|
||||||
|
val trackFiltersIsIgnored = includedTracks.isEmpty() && excludedTracks.isEmpty()
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
val filterLewd = libraryPreferences.filterLewd().get()
|
val filterLewd = libraryPreferences.filterLewd().get()
|
||||||
// SY <--
|
// SY <--
|
||||||
@ -335,25 +323,21 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val filterFnTracking: (LibraryItem) -> Boolean = tracking@{ item ->
|
val filterFnTracking: (LibraryItem) -> Boolean = tracking@{ item ->
|
||||||
if (isNotAnyLoggedIn) return@tracking true
|
if (isNotLoggedInAnyTrack || trackFiltersIsIgnored) return@tracking true
|
||||||
|
|
||||||
val trackedManga = trackMap[item.libraryManga.manga.id]
|
val mangaTracks = trackMap[item.libraryManga.id].orEmpty()
|
||||||
|
|
||||||
val containsExclude = loggedInServices.filterValues { it == State.EXCLUDE.value }
|
val exclude = mangaTracks.filter { it in excludedTracks }
|
||||||
val containsInclude = loggedInServices.filterValues { it == State.INCLUDE.value }
|
val include = mangaTracks.filter { it in includedTracks }
|
||||||
|
|
||||||
if (!containsExclude.any() && !containsInclude.any()) return@tracking true
|
// TODO: Simplify the filter logic
|
||||||
|
if (includedTracks.isNotEmpty() && excludedTracks.isNotEmpty()) {
|
||||||
val exclude = trackedManga?.filter { containsExclude.containsKey(it.key) && it.value }?.values ?: emptyList()
|
return@tracking if (exclude.isNotEmpty()) false else include.isNotEmpty()
|
||||||
val include = trackedManga?.filter { containsInclude.containsKey(it.key) && it.value }?.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 (excludedTracks.isNotEmpty()) return@tracking exclude.isEmpty()
|
||||||
|
|
||||||
if (containsInclude.any()) return@tracking include.any()
|
if (includedTracks.isNotEmpty()) return@tracking include.isNotEmpty()
|
||||||
|
|
||||||
return@tracking false
|
return@tracking false
|
||||||
}
|
}
|
||||||
@ -385,15 +369,13 @@ class LibraryPresenter(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return map.mapValues { entry -> entry.value.filter(filterFn) }
|
return this.mapValues { entry -> entry.value.filter(filterFn) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies library sorting to the given map of manga.
|
* Applies library sorting to the given map of manga.
|
||||||
*
|
|
||||||
* @param map the map to sort.
|
|
||||||
*/
|
*/
|
||||||
private fun applySort(categories: List<Category>, map: LibraryMap): LibraryMap {
|
private fun LibraryMap.applySort(categories: List<Category>): LibraryMap {
|
||||||
// SY -->
|
// SY -->
|
||||||
val listOfTags by lazy {
|
val listOfTags by lazy {
|
||||||
libraryPreferences.sortTagsForLibrary().get()
|
libraryPreferences.sortTagsForLibrary().get()
|
||||||
@ -469,7 +451,7 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return map.mapValues { entry ->
|
return this.mapValues { entry ->
|
||||||
// SY -->
|
// SY -->
|
||||||
val isAscending = if (groupType == LibraryGroup.BY_DEFAULT) {
|
val isAscending = if (groupType == LibraryGroup.BY_DEFAULT) {
|
||||||
sortModes[entry.key]!!.isAscending
|
sortModes[entry.key]!!.isAscending
|
||||||
@ -539,85 +521,47 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
private fun applyGrouping(map: LibraryMap, categories: List<Category>): Pair<LibraryMap, List<Category>> {
|
private fun LibraryMap.applyGrouping(categories: List<Category>): Library {
|
||||||
val groupType = libraryPreferences.groupLibraryBy().get()
|
val groupType = libraryPreferences.groupLibraryBy().get()
|
||||||
var editedCategories = categories
|
var editedCategories = categories
|
||||||
val items = when (groupType) {
|
val items = when (groupType) {
|
||||||
LibraryGroup.BY_DEFAULT -> map
|
LibraryGroup.BY_DEFAULT -> this
|
||||||
LibraryGroup.UNGROUPED -> {
|
LibraryGroup.UNGROUPED -> {
|
||||||
editedCategories = listOf(Category(0, "All", 0, 0))
|
editedCategories = listOf(Category(0, "All", 0, 0))
|
||||||
mapOf(
|
mapOf(
|
||||||
0L to map.values.flatten().distinctBy { it.libraryManga.manga.id },
|
0L to this.values.flatten().distinctBy { it.libraryManga.manga.id },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
val (items, customCategories) = getGroupedMangaItems(
|
val (items, customCategories) = getGroupedMangaItems(
|
||||||
groupType = groupType,
|
groupType = groupType,
|
||||||
libraryManga = map.values.flatten().distinctBy { it.libraryManga.manga.id },
|
libraryManga = this.values.flatten().distinctBy { it.libraryManga.manga.id },
|
||||||
)
|
)
|
||||||
editedCategories = customCategories
|
editedCategories = customCategories
|
||||||
items
|
items
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return items to editedCategories
|
return Library(editedCategories, items)
|
||||||
}
|
}
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the tracked manga from the database and checks if the filter gets changed
|
|
||||||
*
|
|
||||||
* @return an observable of tracked manga.
|
|
||||||
*/
|
|
||||||
private fun getFilterObservable(): Observable<Map<Long, Map<Long, Boolean>>> {
|
|
||||||
return filterTriggerRelay.observeOn(Schedulers.io())
|
|
||||||
.combineLatest(getTracksFlow().asObservable().observeOn(Schedulers.io())) { _, tracks -> tracks }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the tracked manga from the database
|
|
||||||
*
|
|
||||||
* @return an observable of tracked manga.
|
|
||||||
*/
|
|
||||||
private fun getTracksFlow(): Flow<Map<Long, Map<Long, Boolean>>> {
|
|
||||||
// TODO: Move this to domain/data layer
|
|
||||||
return getTracks.subscribe()
|
|
||||||
.map { tracks ->
|
|
||||||
tracks
|
|
||||||
.groupBy { it.mangaId }
|
|
||||||
.mapValues { tracksForMangaId ->
|
|
||||||
// Check if any of the trackers is logged in for the current manga id
|
|
||||||
tracksForMangaId.value.associate {
|
|
||||||
Pair(it.syncId, trackManager.getService(it.syncId)?.isLogged.takeUnless { isLogged -> isLogged == true && it.syncId == TrackManager.MDLIST && it.status == FollowStatus.UNFOLLOWED.int.toLong() } ?: false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests the library to be filtered.
|
* Requests the library to be filtered.
|
||||||
*/
|
*/
|
||||||
fun requestFilterUpdate() {
|
suspend fun requestFilterUpdate() = withIOContext {
|
||||||
filterTriggerRelay.call(Unit)
|
_filterChanges.send(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
/**
|
/**
|
||||||
* Requests the library to have groups refreshed.
|
* Requests the library to be grouped.
|
||||||
*/
|
*/
|
||||||
fun requestGroupsUpdate() {
|
suspend fun requestGroupUpdate() = withIOContext {
|
||||||
groupingTriggerRelay.call(Unit)
|
_groupChanges.send(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SY <--
|
// SY <--
|
||||||
|
|
||||||
/**
|
|
||||||
* Requests the library to be sorted.
|
|
||||||
*/
|
|
||||||
fun requestSortUpdate() {
|
|
||||||
sortTriggerRelay.call(Unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a manga is opened.
|
* Called when a manga is opened.
|
||||||
*/
|
*/
|
||||||
@ -633,9 +577,9 @@ class LibraryPresenter(
|
|||||||
*/
|
*/
|
||||||
suspend fun getCommonCategories(mangas: List<Manga>): Collection<Category> {
|
suspend fun getCommonCategories(mangas: List<Manga>): Collection<Category> {
|
||||||
if (mangas.isEmpty()) return emptyList()
|
if (mangas.isEmpty()) return emptyList()
|
||||||
return mangas.toSet()
|
return mangas
|
||||||
.map { getCategories.await(it.id) }
|
.map { getCategories.await(it.id).toSet() }
|
||||||
.reduce { set1, set2 -> set1.intersect(set2).toMutableList() }
|
.reduce { set1, set2 -> set1.intersect(set2) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -645,9 +589,9 @@ class LibraryPresenter(
|
|||||||
*/
|
*/
|
||||||
suspend fun getMixCategories(mangas: List<Manga>): Collection<Category> {
|
suspend fun getMixCategories(mangas: List<Manga>): Collection<Category> {
|
||||||
if (mangas.isEmpty()) return emptyList()
|
if (mangas.isEmpty()) return emptyList()
|
||||||
val mangaCategories = mangas.toSet().map { getCategories.await(it.id) }
|
val mangaCategories = mangas.map { getCategories.await(it.id).toSet() }
|
||||||
val common = mangaCategories.reduce { set1, set2 -> set1.intersect(set2).toMutableList() }
|
val common = mangaCategories.reduce { set1, set2 -> set1.intersect(set2) }
|
||||||
return mangaCategories.flatten().distinct().subtract(common).toMutableList()
|
return mangaCategories.flatten().distinct().subtract(common)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -789,10 +733,10 @@ class LibraryPresenter(
|
|||||||
*/
|
*/
|
||||||
fun setMangaCategories(mangaList: List<Manga>, addCategories: List<Long>, removeCategories: List<Long>) {
|
fun setMangaCategories(mangaList: List<Manga>, addCategories: List<Long>, removeCategories: List<Long>) {
|
||||||
presenterScope.launchNonCancellable {
|
presenterScope.launchNonCancellable {
|
||||||
mangaList.map { manga ->
|
mangaList.forEach { manga ->
|
||||||
val categoryIds = getCategories.await(manga.id)
|
val categoryIds = getCategories.await(manga.id)
|
||||||
.map { it.id }
|
.map { it.id }
|
||||||
.subtract(removeCategories)
|
.subtract(removeCategories.toSet())
|
||||||
.plus(addCategories)
|
.plus(addCategories)
|
||||||
.toList()
|
.toList()
|
||||||
|
|
||||||
@ -1101,10 +1045,6 @@ class LibraryPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T, U, R> Observable<T>.combineLatest(o2: Observable<U>, combineFn: (T, U) -> R): Observable<R> {
|
|
||||||
return Observable.combineLatest(this, o2, combineFn)
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class Dialog {
|
sealed class Dialog {
|
||||||
data class ChangeCategory(val manga: List<Manga>, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
data class ChangeCategory(val manga: List<Manga>, val initialSelection: List<CheckboxState<Category>>) : Dialog()
|
||||||
data class DeleteManga(val manga: List<Manga>) : Dialog()
|
data class DeleteManga(val manga: List<Manga>) : Dialog()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user