mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-21 20:47:03 -05:00
Avoid going to db when a library filter is changed
This commit is contained in:
parent
aba528b227
commit
3d2a98451b
3 changed files with 74 additions and 77 deletions
|
@ -23,7 +23,7 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) :
|
||||||
/**
|
/**
|
||||||
* The list of manga in this category.
|
* The list of manga in this category.
|
||||||
*/
|
*/
|
||||||
private var mangas: List<Manga>? = null
|
private var mangas: List<Manga> = emptyList()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setHasStableIds(true)
|
setHasStableIds(true)
|
||||||
|
@ -37,7 +37,7 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) :
|
||||||
fun setItems(list: List<Manga>) {
|
fun setItems(list: List<Manga>) {
|
||||||
mItems = list
|
mItems = list
|
||||||
|
|
||||||
// A copy of manga that it's always unfiltered
|
// A copy of manga always unfiltered.
|
||||||
mangas = ArrayList(list)
|
mangas = ArrayList(list)
|
||||||
updateDataSet(null)
|
updateDataSet(null)
|
||||||
}
|
}
|
||||||
|
@ -58,10 +58,8 @@ class LibraryCategoryAdapter(val fragment: LibraryCategoryView) :
|
||||||
* @param param the filter. Not used.
|
* @param param the filter. Not used.
|
||||||
*/
|
*/
|
||||||
override fun updateDataSet(param: String?) {
|
override fun updateDataSet(param: String?) {
|
||||||
mangas?.let {
|
filterItems(mangas)
|
||||||
filterItems(it)
|
notifyDataSetChanged()
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -153,7 +153,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
||||||
if (savedState != null) {
|
if (savedState != null) {
|
||||||
activeCategory = savedState.getInt(CATEGORY_KEY)
|
activeCategory = savedState.getInt(CATEGORY_KEY)
|
||||||
query = savedState.getString(QUERY_KEY)
|
query = savedState.getString(QUERY_KEY)
|
||||||
presenter.searchSubject.onNext(query)
|
presenter.searchSubject.call(query)
|
||||||
if (presenter.selectedMangas.isNotEmpty()) {
|
if (presenter.selectedMangas.isNotEmpty()) {
|
||||||
createActionModeIfNeeded()
|
createActionModeIfNeeded()
|
||||||
}
|
}
|
||||||
|
@ -301,7 +301,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
||||||
* Applies filter change
|
* Applies filter change
|
||||||
*/
|
*/
|
||||||
private fun onFilterOrSortChanged() {
|
private fun onFilterOrSortChanged() {
|
||||||
presenter.resubscribeLibrary()
|
presenter.requestLibraryUpdate()
|
||||||
activity.supportInvalidateOptionsMenu()
|
activity.supportInvalidateOptionsMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +346,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
||||||
|
|
||||||
// Notify the subject the query has changed.
|
// Notify the subject the query has changed.
|
||||||
if (isResumed) {
|
if (isResumed) {
|
||||||
presenter.searchSubject.onNext(query)
|
presenter.searchSubject.call(query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +374,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
|
||||||
view_pager.post { if (isAdded) tabs.setScrollPosition(view_pager.currentItem, 0f, true) }
|
view_pager.post { if (isAdded) tabs.setScrollPosition(view_pager.currentItem, 0f, true) }
|
||||||
|
|
||||||
// Send the manga map to child fragments after the adapter is updated.
|
// Send the manga map to child fragments after the adapter is updated.
|
||||||
presenter.libraryMangaSubject.onNext(LibraryMangaEvent(mangaMap))
|
presenter.libraryMangaSubject.call(LibraryMangaEvent(mangaMap))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,6 +2,8 @@ package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Pair
|
import android.util.Pair
|
||||||
|
import com.jakewharton.rxrelay.BehaviorRelay
|
||||||
|
import com.jakewharton.rxrelay.PublishRelay
|
||||||
import eu.kanade.tachiyomi.Constants
|
import eu.kanade.tachiyomi.Constants
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
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.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.data.source.SourceManager
|
import eu.kanade.tachiyomi.data.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
|
import eu.kanade.tachiyomi.util.isNullOrUnsubscribed
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import rx.subjects.BehaviorSubject
|
|
||||||
import rx.subjects.PublishSubject
|
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
@ -28,6 +30,31 @@ import java.util.*
|
||||||
*/
|
*/
|
||||||
class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database.
|
||||||
|
*/
|
||||||
|
private val db: DatabaseHelper by injectLazy()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preferences.
|
||||||
|
*/
|
||||||
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cover cache.
|
||||||
|
*/
|
||||||
|
private val coverCache: CoverCache by injectLazy()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source manager.
|
||||||
|
*/
|
||||||
|
private val sourceManager: SourceManager by injectLazy()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download manager.
|
||||||
|
*/
|
||||||
|
private val downloadManager: DownloadManager by injectLazy()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Categories of the library.
|
* Categories of the library.
|
||||||
*/
|
*/
|
||||||
|
@ -41,61 +68,52 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
||||||
/**
|
/**
|
||||||
* Search query of the library.
|
* Search query of the library.
|
||||||
*/
|
*/
|
||||||
val searchSubject: BehaviorSubject<String> = BehaviorSubject.create()
|
val searchSubject: BehaviorRelay<String> = BehaviorRelay.create()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subject to notify the library's viewpager for updates.
|
* Subject to notify the library's viewpager for updates.
|
||||||
*/
|
*/
|
||||||
val libraryMangaSubject: BehaviorSubject<LibraryMangaEvent> = BehaviorSubject.create()
|
val libraryMangaSubject: BehaviorRelay<LibraryMangaEvent> = BehaviorRelay.create()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subject to notify the UI of selection updates.
|
* Subject to notify the UI of selection updates.
|
||||||
*/
|
*/
|
||||||
val selectionSubject: PublishSubject<LibrarySelectionEvent> = PublishSubject.create()
|
val selectionSubject: PublishRelay<LibrarySelectionEvent> = PublishRelay.create()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Database.
|
* Relay used to apply the UI filters to the last emission of the library.
|
||||||
*/
|
*/
|
||||||
val db: DatabaseHelper by injectLazy()
|
private val updateTriggerRelay = BehaviorRelay.create(Unit)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preferences.
|
* Library subscription.
|
||||||
*/
|
*/
|
||||||
val preferences: PreferencesHelper by injectLazy()
|
private var librarySubscription: Subscription? = null
|
||||||
|
|
||||||
/**
|
|
||||||
* Cover cache.
|
|
||||||
*/
|
|
||||||
val coverCache: CoverCache by injectLazy()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Source manager.
|
|
||||||
*/
|
|
||||||
val sourceManager: SourceManager by injectLazy()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download manager.
|
|
||||||
*/
|
|
||||||
val downloadManager: DownloadManager by injectLazy()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
/**
|
|
||||||
* Id of the restartable that listens for library updates.
|
|
||||||
*/
|
|
||||||
const val GET_LIBRARY = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedState: Bundle?) {
|
override fun onCreate(savedState: Bundle?) {
|
||||||
super.onCreate(savedState)
|
super.onCreate(savedState)
|
||||||
|
subscribeLibrary()
|
||||||
|
}
|
||||||
|
|
||||||
restartableLatestCache(GET_LIBRARY,
|
/**
|
||||||
{ getLibraryObservable() },
|
* Subscribes to library if needed.
|
||||||
{ view, pair -> view.onNextLibraryUpdate(pair.first, pair.second) })
|
*/
|
||||||
|
fun subscribeLibrary() {
|
||||||
if (savedState == null) {
|
if (librarySubscription.isNullOrUnsubscribed()) {
|
||||||
start(GET_LIBRARY)
|
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.
|
* @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(),
|
return Observable.combineLatest(getCategoriesObservable(), getLibraryMangasObservable(),
|
||||||
{ dbCategories, libraryManga ->
|
{ dbCategories, libraryManga ->
|
||||||
val categories = if (libraryManga.containsKey(0))
|
val categories = if (libraryManga.containsKey(0))
|
||||||
|
@ -114,7 +132,6 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
||||||
this.categories = categories
|
this.categories = categories
|
||||||
Pair(categories, libraryManga)
|
Pair(categories, libraryManga)
|
||||||
})
|
})
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,7 +139,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
||||||
*
|
*
|
||||||
* @return an observable of the categories.
|
* @return an observable of the categories.
|
||||||
*/
|
*/
|
||||||
fun getCategoriesObservable(): Observable<List<Category>> {
|
private fun getCategoriesObservable(): Observable<List<Category>> {
|
||||||
return db.getCategories().asRxObservable()
|
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
|
* @return an observable containing a map with the category id as key and a list of manga as the
|
||||||
* value.
|
* value.
|
||||||
*/
|
*/
|
||||||
fun getLibraryMangasObservable(): Observable<Map<Int, List<Manga>>> {
|
private fun getLibraryMangasObservable(): Observable<Map<Int, List<Manga>>> {
|
||||||
return db.getLibraryMangas().asRxObservable()
|
return db.getLibraryMangas().asRxObservable()
|
||||||
.flatMap {
|
.map { list -> list.groupBy { it.category } }
|
||||||
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.
|
* Requests the library to be filtered.
|
||||||
*/
|
*/
|
||||||
fun subscribeLibrary() {
|
fun requestLibraryUpdate() {
|
||||||
if (isUnsubscribed(GET_LIBRARY)) {
|
updateTriggerRelay.call(Unit)
|
||||||
start(GET_LIBRARY)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resubscribes to library.
|
|
||||||
*/
|
|
||||||
fun resubscribeLibrary() {
|
|
||||||
start(GET_LIBRARY)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -238,7 +237,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
||||||
*/
|
*/
|
||||||
fun onOpenManga() {
|
fun onOpenManga() {
|
||||||
// Avoid further db updates for the library when it's not needed
|
// 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) {
|
fun setSelection(manga: Manga, selected: Boolean) {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
selectedMangas.add(manga)
|
selectedMangas.add(manga)
|
||||||
selectionSubject.onNext(LibrarySelectionEvent.Selected(manga))
|
selectionSubject.call(LibrarySelectionEvent.Selected(manga))
|
||||||
} else {
|
} else {
|
||||||
selectedMangas.remove(manga)
|
selectedMangas.remove(manga)
|
||||||
selectionSubject.onNext(LibrarySelectionEvent.Unselected(manga))
|
selectionSubject.call(LibrarySelectionEvent.Unselected(manga))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +261,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() {
|
||||||
*/
|
*/
|
||||||
fun clearSelections() {
|
fun clearSelections() {
|
||||||
selectedMangas.clear()
|
selectedMangas.clear()
|
||||||
selectionSubject.onNext(LibrarySelectionEvent.Cleared())
|
selectionSubject.call(LibrarySelectionEvent.Cleared())
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue