Recent Read Controller is no longer Rx

Unfortunately to fix #72, an rx observer is needed since the reader adds to the db after the recents is back in view
This commit is contained in:
Jay 2020-02-10 01:02:09 -08:00
parent f91e66269f
commit fb2ab7d765
6 changed files with 130 additions and 85 deletions

View File

@ -96,7 +96,7 @@ class MigrationListController(bundle: Bundle? = null) : BaseController(bundle),
new
}
adapter = MigrationProcessAdapter(this, view.context)
adapter = MigrationProcessAdapter(this)
recycler.adapter = adapter
recycler.layoutManager = LinearLayoutManager(view.context)

View File

@ -16,8 +16,7 @@ import kotlinx.coroutines.withContext
import uy.kohesive.injekt.injectLazy
class MigrationProcessAdapter(
val controller: MigrationListController,
context: Context
val controller: MigrationListController
) : FlexibleAdapter<MigrationProcessItem>(null, controller, true) {

View File

@ -1,35 +1,37 @@
package eu.kanade.tachiyomi.ui.recently_read
import androidx.recyclerview.widget.LinearLayoutManager
import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.SearchView
import com.jakewharton.rxbinding.support.v7.widget.queryTextChanges
import androidx.recyclerview.widget.LinearLayoutManager
import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.backup.BackupRestoreService
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
import eu.kanade.tachiyomi.ui.catalogue.browse.ProgressItem
import eu.kanade.tachiyomi.ui.manga.MangaController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.android.synthetic.main.recently_read_controller.empty_view
import kotlinx.android.synthetic.main.recently_read_controller.recycler
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
import eu.kanade.tachiyomi.util.view.setOnQueryTextChangeListener
import kotlinx.android.synthetic.main.recently_read_controller.*
/**
* Fragment that shows recently read manga.
* Uses R.layout.fragment_recently_read.
* UI related actions should be called from here.
*/
class RecentlyReadController : NucleusController<RecentlyReadPresenter>(),
class RecentlyReadController(bundle: Bundle? = null) : BaseController(bundle),
FlexibleAdapter.OnUpdateListener,
FlexibleAdapter.EndlessScrollListener,
RecentlyReadAdapter.OnRemoveClickListener,
@ -50,16 +52,17 @@ class RecentlyReadController : NucleusController<RecentlyReadPresenter>(),
* Endless loading item.
*/
private var progressItem: ProgressItem? = null
private var observeLater:Boolean = false
private var query = ""
private var presenter = RecentlyReadPresenter(this)
private var recentItems: MutableList<RecentlyReadItem>? = null
override fun getTitle(): String? {
return resources?.getString(R.string.label_recent_manga)
}
override fun createPresenter(): RecentlyReadPresenter {
return RecentlyReadPresenter()
}
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
return inflater.inflate(R.layout.recently_read_controller, container, false)
}
@ -73,38 +76,52 @@ class RecentlyReadController : NucleusController<RecentlyReadPresenter>(),
super.onViewCreated(view)
// Initialize adapter
recycler.layoutManager = LinearLayoutManager(view.context)
adapter = RecentlyReadAdapter(this@RecentlyReadController)
recycler.setHasFixedSize(true)
adapter = RecentlyReadAdapter(this)
recycler.adapter = adapter
recycler.layoutManager = LinearLayoutManager(view.context)
recycler.setHasFixedSize(true)
recycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
resetProgressItem()
if (recentItems != null)
adapter?.updateDataSet(recentItems!!.toList())
launchUI {
val manga = presenter.refresh(query)
recentItems = manga.toMutableList()
adapter?.updateDataSet(manga)
}
}
override fun onDestroyView(view: View) {
adapter = null
super.onDestroyView(view)
override fun onActivityResumed(activity: Activity) {
super.onActivityResumed(activity)
if (observeLater) {
presenter.observe()
observeLater = false
}
}
/**
* Populate adapter with chapters
*
* @param mangaHistory list of manga history
*/
fun onNextManga(mangaHistory: List<RecentlyReadItem>, cleanBatch: Boolean = false) {
if (adapter?.itemCount ?: 0 == 0 || cleanBatch)
fun onNextManga(mangaHistory: List<RecentlyReadItem>) {
val adapter = adapter ?: return
adapter.updateDataSet(mangaHistory)
adapter.onLoadMoreComplete(null)
if (recentItems == null)
resetProgressItem()
if (cleanBatch) adapter?.updateDataSet(mangaHistory)
else adapter?.onLoadMoreComplete(mangaHistory)
recentItems = mangaHistory.toMutableList()
}
fun onAddPageError(error: Throwable) {
fun onAddPageError() {
adapter?.onLoadMoreComplete(null)
adapter?.endlessTargetCount = 1
}
override fun onUpdateEmptyView(size: Int) {
if (size > 0) {
empty_view.hide()
empty_view?.hide()
} else {
empty_view.show(R.drawable.ic_glasses_black_128dp, R.string.information_no_recent_manga)
}
@ -122,17 +139,17 @@ class RecentlyReadController : NucleusController<RecentlyReadPresenter>(),
override fun onLoadMore(lastPosition: Int, currentPage: Int) {
val view = view ?: return
if (BackupRestoreService.isRunning(view.context.applicationContext)) {
onAddPageError(Throwable())
onAddPageError()
return
}
val adapter = adapter ?: return
presenter.requestNext(adapter.itemCount, query)
presenter.requestNext(query)
}
override fun noMoreLoad(newItemsSize: Int) { }
override fun onResumeClick(position: Int) {
val activity = activity ?: return
observeLater = true
val (manga, chapter, _) = (adapter?.getItem(position) as? RecentlyReadItem)?.mch ?: return
val nextChapter = presenter.getNextChapter(chapter, manga)
@ -168,17 +185,24 @@ class RecentlyReadController : NucleusController<RecentlyReadPresenter>(),
inflater.inflate(R.menu.recently_read, menu)
val searchItem = menu.findItem(R.id.action_search)
val searchView = searchItem.actionView as SearchView
searchView.maxWidth = Int.MAX_VALUE
if (query.isNotEmpty()) {
searchItem.expandActionView()
searchView.setQuery(query, true)
searchView.clearFocus()
}
searchView.queryTextChanges().filter { router.backstack.lastOrNull()?.controller() == this }
.subscribeUntilDestroy {
query = it.toString()
presenter.updateList(query)
setOnQueryTextChangeListener(searchView) {
if (query != it) {
query = it ?: return@setOnQueryTextChangeListener false
launchUI {
resetProgressItem()
presenter.lastCount = 25
val manga = presenter.refresh(query)
recentItems = manga.toMutableList()
adapter?.updateDataSet(manga)
}
}
true
}
// Fixes problem with the overflow icon showing up in lieu of search
searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {

View File

@ -6,6 +6,10 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.History
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.util.system.launchUI
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.Dispatcher
import rx.Observable
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
@ -20,60 +24,47 @@ import java.util.Date
* Contains information and data for fragment.
* Observable updates should be called from here.
*/
class RecentlyReadPresenter : BasePresenter<RecentlyReadController>() {
class RecentlyReadPresenter(private val view: RecentlyReadController) {
/**
* Used to connect to database
*/
val db: DatabaseHelper by injectLazy()
private var readerSubscription:Subscription? = null
var lastCount = 25
var lastSearch = ""
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
//pageSubscription?.let { remove(it) }
// Used to get a list of recently read manga
updateList()
}
fun requestNext(offset: Int, search: String = "") {
lastCount = offset
fun requestNext(search: String = "") {
lastCount += 25
lastSearch = search
getRecentMangaObservable((offset), search)
.subscribeLatestCache({ view, mangas ->
view.onNextManga(mangas)
}, RecentlyReadController::onAddPageError)
updateList(search)
}
/**
* Get recent manga observable
* Get all recent manga up to a point
* @return list of history
*/
private fun getRecentMangaObservable(offset: Int = 0, search: String = ""): Observable<List<RecentlyReadItem>> {
private fun getRecentMangaLimit(search: String = ""): List<RecentlyReadItem> {
// Set date for recent manga
val cal = Calendar.getInstance()
cal.time = Date()
cal.add(Calendar.YEAR, -50)
return db.getRecentManga(cal.time, offset, search).asRxObservable()
.map { recents -> recents.map(::RecentlyReadItem) }
.observeOn(AndroidSchedulers.mainThread())
return db.getRecentMangaLimit(cal.time, lastCount, search).executeAsBlocking()
.map(::RecentlyReadItem)
}
/**
* Get recent manga observable
* @return list of history
*/
private fun getRecentMangaLimitObservable(offset: Int = 0, search: String = ""): Observable<List<RecentlyReadItem>> {
// Set date for recent manga
fun observe() {
readerSubscription?.unsubscribe()
val cal = Calendar.getInstance()
cal.time = Date()
cal.add(Calendar.YEAR, -50)
return db.getRecentMangaLimit(cal.time, lastCount, search).asRxObservable()
.map { recents -> recents.map(::RecentlyReadItem) }
.observeOn(AndroidSchedulers.mainThread())
readerSubscription = db.getRecentMangaLimit(cal.time, lastCount, "").asRxObservable().map {
val items = it.map(::RecentlyReadItem)
launchUI {
view.onNextManga(items)
}
}.observeOn(Schedulers.io()).skip(1).take(1).subscribe()
}
/**
@ -86,12 +77,28 @@ class RecentlyReadPresenter : BasePresenter<RecentlyReadController>() {
updateList()
}
fun updateList(search: String? = null) {
lastSearch = search?:lastSearch
getRecentMangaLimitObservable(lastCount, lastSearch).take(1)
.subscribeLatestCache({ view, mangas ->
view.onNextManga(mangas, true)
}, RecentlyReadController::onAddPageError)
suspend fun refresh(search: String? = null): List<RecentlyReadItem> {
val manga = withContext(Dispatchers.IO) { getRecentMangaLimit(search ?: "") }
checkIfNew(manga.size, search)
lastSearch = search ?: lastSearch
lastCount = manga.size
return manga
}
private fun updateList(search: String? = null) {
launchUI {
val manga = withContext(Dispatchers.IO) { getRecentMangaLimit(search ?: "") }
checkIfNew(manga.size, search)
lastSearch = search ?: lastSearch
lastCount = manga.size
view.onNextManga(manga)
}
}
private fun checkIfNew(newCount: Int, newSearch: String?) {
if (lastCount > newCount && newSearch == lastSearch) {
view.onAddPageError()
}
}
/**

View File

@ -13,14 +13,12 @@ import android.widget.TextView
import androidx.annotation.Px
import androidx.annotation.RequiresApi
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.appcompat.widget.SearchView
import androidx.core.view.ViewCompat
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.WhichButton
import com.afollestad.materialdialogs.actions.getActionButton
import com.afollestad.materialdialogs.actions.hasActionButton
import com.amulyakhare.textdrawable.TextDrawable
import eu.kanade.tachiyomi.R
import com.amulyakhare.textdrawable.util.ColorGenerator
import com.bluelinelabs.conductor.Controller
import com.google.android.material.snackbar.Snackbar
import eu.kanade.tachiyomi.util.system.getResourceColor
import kotlin.math.min
@ -199,6 +197,22 @@ data class ViewPaddingState(
val end: Int
)
fun Controller.setOnQueryTextChangeListener(searchView: SearchView, f: (text: String?) -> Boolean) {
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextChange(newText: String?): Boolean {
if (router.backstack.lastOrNull()?.controller() == this@setOnQueryTextChangeListener) {
return f(newText)
}
return true
}
override fun onQueryTextSubmit(query: String?): Boolean {
return true
}
})
}
@RequiresApi(17)
inline fun View.updatePaddingRelative(
@Px start: Int = paddingStart,

View File

@ -1,26 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/frame_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:clipToPadding="false"
android:paddingTop="4dp"
android:paddingBottom="4dp"
tools:listitem="@layout/recently_read_item">
</androidx.recyclerview.widget.RecyclerView>
<eu.kanade.tachiyomi.widget.EmptyView
android:id="@+id/empty_view"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_height="wrap_content"/>
android:visibility="gone" />
</FrameLayout>