|
|
|
@ -2,6 +2,8 @@ package eu.kanade.tachiyomi.ui.library
|
|
|
|
|
|
|
|
|
|
import android.os.Bundle
|
|
|
|
|
import android.util.Pair
|
|
|
|
|
import com.jakewharton.rxrelay.BehaviorRelay
|
|
|
|
|
import com.jakewharton.rxrelay.PublishRelay
|
|
|
|
|
import eu.kanade.tachiyomi.Constants
|
|
|
|
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
|
|
|
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|
|
|
@ -13,11 +15,11 @@ import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
|
|
|
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
|
|
|
|
import eu.kanade.tachiyomi.data.source.SourceManager
|
|
|
|
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
|
|
|
|
import eu.kanade.tachiyomi.util.isNullOrUnsubscribed
|
|
|
|
|
import rx.Observable
|
|
|
|
|
import rx.Subscription
|
|
|
|
|
import rx.android.schedulers.AndroidSchedulers
|
|
|
|
|
import rx.schedulers.Schedulers
|
|
|
|
|
import rx.subjects.BehaviorSubject
|
|
|
|
|
import rx.subjects.PublishSubject
|
|
|
|
|
import uy.kohesive.injekt.injectLazy
|
|
|
|
|
import java.io.IOException
|
|
|
|
|
import java.io.InputStream
|
|
|
|
@ -29,73 +31,89 @@ import java.util.*
|
|
|
|
|
class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Categories of the library.
|
|
|
|
|
* Database.
|
|
|
|
|
*/
|
|
|
|
|
var categories: List<Category> = emptyList()
|
|
|
|
|
private val db: DatabaseHelper by injectLazy()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Currently selected manga.
|
|
|
|
|
* Preferences.
|
|
|
|
|
*/
|
|
|
|
|
val selectedMangas = mutableListOf<Manga>()
|
|
|
|
|
private val preferences: PreferencesHelper by injectLazy()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Search query of the library.
|
|
|
|
|
* Cover cache.
|
|
|
|
|
*/
|
|
|
|
|
val searchSubject: BehaviorSubject<String> = BehaviorSubject.create()
|
|
|
|
|
private val coverCache: CoverCache by injectLazy()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Subject to notify the library's viewpager for updates.
|
|
|
|
|
* Source manager.
|
|
|
|
|
*/
|
|
|
|
|
val libraryMangaSubject: BehaviorSubject<LibraryMangaEvent> = BehaviorSubject.create()
|
|
|
|
|
private val sourceManager: SourceManager by injectLazy()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Subject to notify the UI of selection updates.
|
|
|
|
|
* Download manager.
|
|
|
|
|
*/
|
|
|
|
|
val selectionSubject: PublishSubject<LibrarySelectionEvent> = PublishSubject.create()
|
|
|
|
|
private val downloadManager: DownloadManager by injectLazy()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Database.
|
|
|
|
|
* Categories of the library.
|
|
|
|
|
*/
|
|
|
|
|
val db: DatabaseHelper by injectLazy()
|
|
|
|
|
var categories: List<Category> = emptyList()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Preferences.
|
|
|
|
|
* Currently selected manga.
|
|
|
|
|
*/
|
|
|
|
|
val preferences: PreferencesHelper by injectLazy()
|
|
|
|
|
val selectedMangas = mutableListOf<Manga>()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Cover cache.
|
|
|
|
|
* Search query of the library.
|
|
|
|
|
*/
|
|
|
|
|
val coverCache: CoverCache by injectLazy()
|
|
|
|
|
val searchSubject: BehaviorRelay<String> = BehaviorRelay.create()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Source manager.
|
|
|
|
|
* Subject to notify the library's viewpager for updates.
|
|
|
|
|
*/
|
|
|
|
|
val sourceManager: SourceManager by injectLazy()
|
|
|
|
|
val libraryMangaSubject: BehaviorRelay<LibraryMangaEvent> = BehaviorRelay.create()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Download manager.
|
|
|
|
|
* Subject to notify the UI of selection updates.
|
|
|
|
|
*/
|
|
|
|
|
val downloadManager: DownloadManager by injectLazy()
|
|
|
|
|
val selectionSubject: PublishRelay<LibrarySelectionEvent> = PublishRelay.create()
|
|
|
|
|
|
|
|
|
|
companion object {
|
|
|
|
|
/**
|
|
|
|
|
* Id of the restartable that listens for library updates.
|
|
|
|
|
*/
|
|
|
|
|
const val GET_LIBRARY = 1
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Relay used to apply the UI filters to the last emission of the library.
|
|
|
|
|
*/
|
|
|
|
|
private val updateTriggerRelay = BehaviorRelay.create(Unit)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Library subscription.
|
|
|
|
|
*/
|
|
|
|
|
private var librarySubscription: Subscription? = null
|
|
|
|
|
|
|
|
|
|
override fun onCreate(savedState: Bundle?) {
|
|
|
|
|
super.onCreate(savedState)
|
|
|
|
|
subscribeLibrary()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
restartableLatestCache(GET_LIBRARY,
|
|
|
|
|
{ getLibraryObservable() },
|
|
|
|
|
{ view, pair -> view.onNextLibraryUpdate(pair.first, pair.second) })
|
|
|
|
|
|
|
|
|
|
if (savedState == null) {
|
|
|
|
|
start(GET_LIBRARY)
|
|
|
|
|
/**
|
|
|
|
|
* Subscribes to library if needed.
|
|
|
|
|
*/
|
|
|
|
|
fun subscribeLibrary() {
|
|
|
|
|
if (librarySubscription.isNullOrUnsubscribed()) {
|
|
|
|
|
librarySubscription = Observable.combineLatest(getLibraryObservable(),
|
|
|
|
|
updateTriggerRelay.observeOn(Schedulers.io()),
|
|
|
|
|
{ library, updateTrigger -> library })
|
|
|
|
|
.map { Pair(it.first, applyFilters(it.second)) }
|
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
|
.subscribeLatestCache({ view, pair -> view.onNextLibraryUpdate(pair.first, pair.second) })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun applyFilters(map: Map<Int, List<Manga>>): Map<Int, List<Manga>> {
|
|
|
|
|
return map.mapValues { entry -> entry.value
|
|
|
|
|
.filter { filterManga(it) }
|
|
|
|
|
.sortedWith(Comparator<Manga> { m1, m2 -> sortManga(m1, m2) })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -103,7 +121,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|
|
|
|
*
|
|
|
|
|
* @return an observable of the categories and its manga.
|
|
|
|
|
*/
|
|
|
|
|
fun getLibraryObservable(): Observable<Pair<List<Category>, Map<Int, List<Manga>>>> {
|
|
|
|
|
private fun getLibraryObservable(): Observable<Pair<List<Category>, Map<Int, List<Manga>>>> {
|
|
|
|
|
return Observable.combineLatest(getCategoriesObservable(), getLibraryMangasObservable(),
|
|
|
|
|
{ dbCategories, libraryManga ->
|
|
|
|
|
val categories = if (libraryManga.containsKey(0))
|
|
|
|
@ -114,7 +132,6 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|
|
|
|
this.categories = categories
|
|
|
|
|
Pair(categories, libraryManga)
|
|
|
|
|
})
|
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -122,7 +139,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|
|
|
|
*
|
|
|
|
|
* @return an observable of the categories.
|
|
|
|
|
*/
|
|
|
|
|
fun getCategoriesObservable(): Observable<List<Category>> {
|
|
|
|
|
private fun getCategoriesObservable(): Observable<List<Category>> {
|
|
|
|
|
return db.getCategories().asRxObservable()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -132,34 +149,16 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|
|
|
|
* @return an observable containing a map with the category id as key and a list of manga as the
|
|
|
|
|
* value.
|
|
|
|
|
*/
|
|
|
|
|
fun getLibraryMangasObservable(): Observable<Map<Int, List<Manga>>> {
|
|
|
|
|
private fun getLibraryMangasObservable(): Observable<Map<Int, List<Manga>>> {
|
|
|
|
|
return db.getLibraryMangas().asRxObservable()
|
|
|
|
|
.flatMap {
|
|
|
|
|
Observable.from(it)
|
|
|
|
|
// Filter library by options
|
|
|
|
|
.filter { filterManga(it) }
|
|
|
|
|
.toSortedList { manga1, manga2 -> sortManga(manga1, manga2) }
|
|
|
|
|
.flatMap { Observable.from(it) }
|
|
|
|
|
.groupBy { it.category }
|
|
|
|
|
.flatMap { group -> group.toList().map { Pair(group.key, it) } }
|
|
|
|
|
.toMap({ it.first }, { it.second })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resubscribes to library if needed.
|
|
|
|
|
*/
|
|
|
|
|
fun subscribeLibrary() {
|
|
|
|
|
if (isUnsubscribed(GET_LIBRARY)) {
|
|
|
|
|
start(GET_LIBRARY)
|
|
|
|
|
}
|
|
|
|
|
.map { list -> list.groupBy { it.category } }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Resubscribes to library.
|
|
|
|
|
* Requests the library to be filtered.
|
|
|
|
|
*/
|
|
|
|
|
fun resubscribeLibrary() {
|
|
|
|
|
start(GET_LIBRARY)
|
|
|
|
|
fun requestLibraryUpdate() {
|
|
|
|
|
updateTriggerRelay.call(Unit)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -238,7 +237,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|
|
|
|
*/
|
|
|
|
|
fun onOpenManga() {
|
|
|
|
|
// Avoid further db updates for the library when it's not needed
|
|
|
|
|
stop(GET_LIBRARY)
|
|
|
|
|
librarySubscription?.let { remove(it) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -250,10 +249,10 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|
|
|
|
fun setSelection(manga: Manga, selected: Boolean) {
|
|
|
|
|
if (selected) {
|
|
|
|
|
selectedMangas.add(manga)
|
|
|
|
|
selectionSubject.onNext(LibrarySelectionEvent.Selected(manga))
|
|
|
|
|
selectionSubject.call(LibrarySelectionEvent.Selected(manga))
|
|
|
|
|
} else {
|
|
|
|
|
selectedMangas.remove(manga)
|
|
|
|
|
selectionSubject.onNext(LibrarySelectionEvent.Unselected(manga))
|
|
|
|
|
selectionSubject.call(LibrarySelectionEvent.Unselected(manga))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -262,7 +261,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
|
|
|
|
*/
|
|
|
|
|
fun clearSelections() {
|
|
|
|
|
selectedMangas.clear()
|
|
|
|
|
selectionSubject.onNext(LibrarySelectionEvent.Cleared())
|
|
|
|
|
selectionSubject.call(LibrarySelectionEvent.Cleared())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|