Mitigate most of the lag problems, should fix all crashes(inspired by J2k code)
Add tracking button the way J2K has it, my own implementation
This commit is contained in:
parent
e6f5ea172a
commit
4a64bb250d
@ -22,8 +22,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.gson.Gson
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.SelectableAdapter
|
||||
import eu.kanade.tachiyomi.R
|
||||
@ -35,6 +33,7 @@ import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.databinding.MangaAllInOneControllerBinding
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
@ -56,6 +55,7 @@ import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersAdapter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersPresenter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.DeleteChaptersDialog
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.DownloadCustomChaptersDialog
|
||||
import eu.kanade.tachiyomi.ui.manga.track.TrackController
|
||||
import eu.kanade.tachiyomi.ui.migration.manga.design.PreMigrationController
|
||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||
import eu.kanade.tachiyomi.ui.recent.history.HistoryController
|
||||
@ -178,12 +178,8 @@ class MangaAllInOneController :
|
||||
|
||||
private var initialLoad: Boolean = true
|
||||
|
||||
// EXH -->
|
||||
private var lastMangaThumbnail: String? = null
|
||||
|
||||
// EXH -->
|
||||
val smartSearchConfig: SourceController.SmartSearchConfig? = args.getParcelable(SMART_SEARCH_CONFIG_EXTRA)
|
||||
// EXH <--
|
||||
|
||||
override val coroutineContext: CoroutineContext = Job() + Dispatchers.Main
|
||||
|
||||
@ -192,12 +188,6 @@ class MangaAllInOneController :
|
||||
private val sourceManager: SourceManager by injectLazy()
|
||||
// EXH <--
|
||||
|
||||
val lastUpdateRelay: BehaviorRelay<Date> = BehaviorRelay.create()
|
||||
|
||||
val chapterCountRelay: BehaviorRelay<Float> = BehaviorRelay.create()
|
||||
|
||||
val mangaFavoriteRelay: PublishRelay<Boolean> = PublishRelay.create()
|
||||
|
||||
val fromSource = args.getBoolean(FROM_SOURCE_EXTRA, false)
|
||||
|
||||
var update = args.getBoolean(UPDATE_EXTRA, false)
|
||||
@ -212,8 +202,7 @@ class MangaAllInOneController :
|
||||
|
||||
override fun createPresenter(): MangaAllInOnePresenter {
|
||||
return MangaAllInOnePresenter(
|
||||
manga!!, source!!,
|
||||
chapterCountRelay, lastUpdateRelay, mangaFavoriteRelay, smartSearchConfig
|
||||
this, manga!!, source!!, smartSearchConfig
|
||||
)
|
||||
}
|
||||
|
||||
@ -232,6 +221,26 @@ class MangaAllInOneController :
|
||||
.onEach { onFavoriteClick() }
|
||||
.launchIn(scope)
|
||||
|
||||
if ((Injekt.get<TrackManager>().hasLoggedServices()) && presenter.manga.favorite) {
|
||||
binding.btnTracking.visible()
|
||||
}
|
||||
|
||||
scope.launch(Dispatchers.IO) {
|
||||
if (Injekt.get<DatabaseHelper>().getTracks(presenter.manga).executeAsBlocking().any {
|
||||
val status = Injekt.get<TrackManager>().getService(it.sync_id)?.getStatus(it.status)
|
||||
status != null
|
||||
}
|
||||
) {
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.btnTracking.icon = resources!!.getDrawable(R.drawable.ic_cloud_white_24dp, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
binding.btnTracking.clicks()
|
||||
.onEach { openTracking() }
|
||||
.launchIn(scope)
|
||||
|
||||
if (presenter.manga.favorite && presenter.getCategories().isNotEmpty()) {
|
||||
binding.btnCategories.visible()
|
||||
}
|
||||
@ -440,6 +449,12 @@ class MangaAllInOneController :
|
||||
}
|
||||
// AZ <--
|
||||
|
||||
private fun openTracking() {
|
||||
router?.pushController(
|
||||
TrackController(fromAllInOne = true, manga = manga).withFadeTransaction()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if manga is initialized.
|
||||
* If true update view with manga information,
|
||||
@ -448,10 +463,10 @@ class MangaAllInOneController :
|
||||
* @param manga manga object containing information about manga.
|
||||
* @param source the source of the manga.
|
||||
*/
|
||||
fun onNextManga(manga: Manga, source: Source) {
|
||||
fun onNextManga(manga: Manga, source: Source, chapters: List<ChapterItem>) {
|
||||
if (manga.initialized) {
|
||||
// Update view.
|
||||
setMangaInfo(manga, source)
|
||||
setMangaInfo(manga, source, chapters)
|
||||
} else {
|
||||
// Initialize manga.
|
||||
fetchMangaFromSource()
|
||||
@ -464,7 +479,7 @@ class MangaAllInOneController :
|
||||
* @param manga manga object containing information about manga.
|
||||
* @param source the source of the manga.
|
||||
*/
|
||||
private fun setMangaInfo(manga: Manga, source: Source?) {
|
||||
private fun setMangaInfo(manga: Manga, source: Source?, chapters: List<ChapterItem>) {
|
||||
val view = view ?: return
|
||||
|
||||
// update full title TextView.
|
||||
@ -579,6 +594,35 @@ class MangaAllInOneController :
|
||||
initialLoad = false
|
||||
}
|
||||
}
|
||||
if (update ||
|
||||
// Auto-update old format galleries
|
||||
(
|
||||
(presenter.manga.source == EH_SOURCE_ID || presenter.manga.source == EXH_SOURCE_ID) &&
|
||||
chapters.size == 1 && chapters.first().date_upload == 0L
|
||||
)
|
||||
) {
|
||||
update = false
|
||||
fetchMangaFromSource()
|
||||
}
|
||||
|
||||
val adapter = adapter ?: return
|
||||
adapter.updateDataSet(chapters)
|
||||
|
||||
if (selectedItems.isNotEmpty()) {
|
||||
adapter.clearSelection() // we need to start from a clean state, index may have changed
|
||||
createActionModeIfNeeded()
|
||||
selectedItems.forEach { item ->
|
||||
val position = adapter.indexOf(item)
|
||||
if (position != -1 && !adapter.isSelected(position)) {
|
||||
adapter.toggleSelection(position)
|
||||
}
|
||||
}
|
||||
actionMode?.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
fun setTracking() {
|
||||
binding.btnTracking.icon = resources!!.getDrawable(R.drawable.ic_cloud_white_24dp, null)
|
||||
}
|
||||
|
||||
private fun hideMangaInfo() {
|
||||
@ -721,14 +765,7 @@ class MangaAllInOneController :
|
||||
presenter.fetchMangaFromSource(manualFetch)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update swipe refresh to stop showing refresh in progress spinner.
|
||||
*/
|
||||
fun onFetchMangaDone() {
|
||||
fetchChaptersFromSource()
|
||||
}
|
||||
|
||||
fun onFetchChaptersDone() {
|
||||
setRefreshing(false)
|
||||
}
|
||||
|
||||
@ -745,7 +782,7 @@ class MangaAllInOneController :
|
||||
*
|
||||
* @param value whether it should be refreshing or not.
|
||||
*/
|
||||
private fun setRefreshing(value: Boolean) {
|
||||
fun setRefreshing(value: Boolean) {
|
||||
binding.swipeRefresh.isRefreshing = value
|
||||
}
|
||||
|
||||
@ -999,56 +1036,6 @@ class MangaAllInOneController :
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
fun onNextChapters(chapters: List<ChapterItem>) {
|
||||
// If the list is empty, fetch chapters from source if the conditions are met
|
||||
// We use presenter chapters instead because they are always unfiltered
|
||||
if (presenter.chapters.isEmpty()) {
|
||||
initialFetchChapters()
|
||||
}
|
||||
|
||||
if (update ||
|
||||
// Auto-update old format galleries
|
||||
(
|
||||
(presenter.manga.source == EH_SOURCE_ID || presenter.manga.source == EXH_SOURCE_ID) &&
|
||||
chapters.size == 1 && chapters.first().date_upload == 0L
|
||||
)
|
||||
) {
|
||||
update = false
|
||||
fetchChaptersFromSource()
|
||||
}
|
||||
|
||||
val adapter = adapter ?: return
|
||||
adapter.updateDataSet(chapters)
|
||||
|
||||
if (selectedItems.isNotEmpty()) {
|
||||
adapter.clearSelection() // we need to start from a clean state, index may have changed
|
||||
createActionModeIfNeeded()
|
||||
selectedItems.forEach { item ->
|
||||
val position = adapter.indexOf(item)
|
||||
if (position != -1 && !adapter.isSelected(position)) {
|
||||
adapter.toggleSelection(position)
|
||||
}
|
||||
}
|
||||
actionMode?.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initialFetchChapters() {
|
||||
// Only fetch if this view is from the catalog and it hasn't requested previously
|
||||
if (fromSource && !presenter.hasRequested) {
|
||||
fetchChaptersFromSource()
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchChaptersFromSource() {
|
||||
presenter.fetchChaptersFromSource()
|
||||
}
|
||||
|
||||
fun onFetchChaptersError(error: Throwable) {
|
||||
onFetchChaptersDone()
|
||||
activity?.toast(error.message)
|
||||
}
|
||||
|
||||
fun onChapterStatusChange(download: Download) {
|
||||
getHolder(download.chapter)?.notifyStatus(download.status)
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.manga
|
||||
import android.os.Bundle
|
||||
import com.google.gson.Gson
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
@ -15,23 +14,27 @@ import eu.kanade.tachiyomi.data.download.model.Download
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.ui.browse.source.SourceController
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersPresenter
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
||||
import eu.kanade.tachiyomi.util.isLocal
|
||||
import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import exh.EH_SOURCE_ID
|
||||
import exh.EXH_SOURCE_ID
|
||||
import exh.MERGED_SOURCE_ID
|
||||
import exh.debug.DebugToggles
|
||||
import exh.eh.EHentaiUpdateHelper
|
||||
import exh.isEhBasedSource
|
||||
import exh.util.await
|
||||
import java.util.Date
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
@ -48,11 +51,9 @@ import uy.kohesive.injekt.injectLazy
|
||||
* Observable updates should be called from here.
|
||||
*/
|
||||
class MangaAllInOnePresenter(
|
||||
val controller: MangaAllInOneController,
|
||||
val manga: Manga,
|
||||
val source: Source,
|
||||
private val chapterCountRelay: BehaviorRelay<Float>,
|
||||
private val lastUpdateRelay: BehaviorRelay<Date>,
|
||||
private val mangaFavoriteRelay: PublishRelay<Boolean>,
|
||||
val smartSearchConfig: SourceController.SmartSearchConfig?,
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
private val downloadManager: DownloadManager = Injekt.get(),
|
||||
@ -67,11 +68,7 @@ class MangaAllInOnePresenter(
|
||||
var chapters: List<ChapterItem> = emptyList()
|
||||
private set
|
||||
|
||||
/**
|
||||
* Subject of list of chapters to allow updating the view without going to DB.
|
||||
*/
|
||||
val chaptersRelay: PublishRelay<List<ChapterItem>>
|
||||
by lazy { PublishRelay.create<List<ChapterItem>>() }
|
||||
private val scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
|
||||
/**
|
||||
* Whether the chapter list has been requested to the source.
|
||||
@ -79,11 +76,6 @@ class MangaAllInOnePresenter(
|
||||
var hasRequested = false
|
||||
private set
|
||||
|
||||
/**
|
||||
* Subscription to retrieve the new list of chapters from the source.
|
||||
*/
|
||||
private var fetchChaptersSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* Subscription to observe download status changes.
|
||||
*/
|
||||
@ -95,67 +87,31 @@ class MangaAllInOnePresenter(
|
||||
val redirectUserRelay = BehaviorRelay.create<ChaptersPresenter.EXHRedirect>()
|
||||
// EXH <--
|
||||
|
||||
/**
|
||||
* Subscription to send the manga to the view.
|
||||
*/
|
||||
private var viewMangaSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* Subscription to update the manga from the source.
|
||||
*/
|
||||
private var fetchMangaSubscription: Subscription? = null
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
|
||||
getMangaObservable()
|
||||
.subscribeLatestCache({ view, manga -> view.onNextManga(manga, source) })
|
||||
|
||||
// Update chapter count
|
||||
chapterCountRelay.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeLatestCache(MangaAllInOneController::setChapterCount)
|
||||
|
||||
// Prepare the relay.
|
||||
chaptersRelay.flatMap { applyChapterFilters(it) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeLatestCache(MangaAllInOneController::onNextChapters) { _, error -> Timber.e(error) }
|
||||
|
||||
// Add the subscription that retrieves the chapters from the database, keeps subscribed to
|
||||
// changes, and sends the list of chapters to the relay.
|
||||
add(
|
||||
db.getChapters(manga).asRxObservable()
|
||||
.map { chapters ->
|
||||
// Convert every chapter to a model.
|
||||
chapters.map { it.toModel() }
|
||||
if (manga.isLocal()) {
|
||||
controller.setRefreshing(true)
|
||||
fetchMangaFromSource()
|
||||
} else if (!manga.initialized) {
|
||||
controller.setRefreshing(true)
|
||||
fetchMangaFromSource()
|
||||
} else {
|
||||
updateManga()
|
||||
}
|
||||
.doOnNext { chapters ->
|
||||
// Find downloaded chapters
|
||||
setDownloadedChapters(chapters)
|
||||
|
||||
// Store the last emission
|
||||
this.chapters = chapters
|
||||
|
||||
// Listen for download status changes
|
||||
observeDownloads()
|
||||
}
|
||||
|
||||
// Emit the number of chapters to the info tab.
|
||||
chapterCountRelay.call(
|
||||
chapters.maxBy { it.chapter_number }?.chapter_number
|
||||
?: 0f
|
||||
)
|
||||
private fun updateChapters() {
|
||||
val chapters = db.getChapters(manga).executeAsBlocking().map { it.toModel() }
|
||||
|
||||
// Find downloaded chapters
|
||||
setDownloadedChapters(chapters)
|
||||
|
||||
// Emit the upload date of the most recent chapter
|
||||
lastUpdateRelay.call(
|
||||
Date(
|
||||
chapters.maxBy { it.date_upload }?.date_upload
|
||||
?: 0
|
||||
)
|
||||
)
|
||||
// EXH -->
|
||||
if (chapters.isNotEmpty() &&
|
||||
(source.id == EXH_SOURCE_ID || source.id == EH_SOURCE_ID) &&
|
||||
DebugToggles.ENABLE_EXH_ROOT_REDIRECT.enabled
|
||||
) {
|
||||
if (chapters.isNotEmpty() && (source.isEhBasedSource()) && DebugToggles.ENABLE_EXH_ROOT_REDIRECT.enabled) {
|
||||
// Check for gallery in library and accept manga with lowest id
|
||||
// Find chapters sharing same root
|
||||
add(
|
||||
@ -179,46 +135,88 @@ class MangaAllInOnePresenter(
|
||||
)
|
||||
}
|
||||
// EXH <--
|
||||
|
||||
this.chapters = applyChapterFilters(chapters)
|
||||
}
|
||||
.subscribe { chaptersRelay.call(it) }
|
||||
|
||||
private fun updateChapterInfo() {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
val lastUpdateDate = Date(
|
||||
chapters.maxBy { it.date_upload }?.date_upload ?: 0
|
||||
)
|
||||
|
||||
// Update favorite status
|
||||
mangaFavoriteRelay.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { setFavorite(it) }
|
||||
.apply { add(this) }
|
||||
val chapterCount = chapters.maxBy { it.chapter_number }?.chapter_number ?: 0f
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
// set chapter count
|
||||
controller.setChapterCount(chapterCount)
|
||||
// update last update date
|
||||
lastUpdateRelay.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeLatestCache(MangaAllInOneController::setLastUpdateDate)
|
||||
controller.setLastUpdateDate(lastUpdateDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMangaObservable(): Observable<Manga> {
|
||||
return db.getManga(manga.url, manga.source).asRxObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
private fun updateManga() {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
val manga = db.getManga(manga.url, manga.source).executeAsBlocking()!!
|
||||
updateChapters()
|
||||
updateChapterInfo()
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
controller.onNextManga(
|
||||
manga, source, chapters
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch manga information from source.
|
||||
*/
|
||||
fun fetchMangaFromSource(manualFetch: Boolean = false) {
|
||||
if (!fetchMangaSubscription.isNullOrUnsubscribed()) return
|
||||
fetchMangaSubscription = Observable.defer { source.fetchMangaDetails(manga) }
|
||||
.map { networkManga ->
|
||||
fun fetchMangaFromSource(manualFetch: Boolean = false, FetchManga: Boolean = true, FetchChapters: Boolean = true) {
|
||||
hasRequested = true
|
||||
|
||||
scope.launch(Dispatchers.IO) {
|
||||
if (FetchManga) {
|
||||
val networkManga = try {
|
||||
source.fetchMangaDetails(manga).toBlocking().single()
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) { controller.onFetchMangaError(e) }
|
||||
return@launch
|
||||
}
|
||||
if (networkManga != null) {
|
||||
manga.prepUpdateCover(coverCache, networkManga, manualFetch)
|
||||
manga.copyFrom(networkManga)
|
||||
manga.initialized = true
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
manga
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
{ view, _ ->
|
||||
view.onFetchMangaDone()
|
||||
},
|
||||
MangaAllInOneController::onFetchMangaError
|
||||
)
|
||||
}
|
||||
var chapters: List<SChapter> = listOf()
|
||||
if (FetchChapters) {
|
||||
try {
|
||||
chapters = source.fetchChapterList(manga).toBlocking().single()
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) { controller.onFetchMangaError(e) }
|
||||
return@launch
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (FetchChapters) {
|
||||
syncChaptersWithSource(db, chapters, manga, source)
|
||||
|
||||
updateChapters()
|
||||
updateChapterInfo()
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
controller.onNextManga(this@MangaAllInOnePresenter.manga, this@MangaAllInOnePresenter.source, this@MangaAllInOnePresenter.chapters)
|
||||
controller.onFetchMangaDone()
|
||||
}
|
||||
} catch (e: java.lang.Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
controller.onFetchMangaError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -404,49 +402,23 @@ class MangaAllInOnePresenter(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests an updated list of chapters from the source.
|
||||
*/
|
||||
fun fetchChaptersFromSource() {
|
||||
hasRequested = true
|
||||
|
||||
if (!fetchChaptersSubscription.isNullOrUnsubscribed()) return
|
||||
fetchChaptersSubscription = Observable.defer { source.fetchChapterList(manga) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.map { syncChaptersWithSource(db, it, manga, source) }
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
{ view, _ ->
|
||||
view.onFetchChaptersDone()
|
||||
},
|
||||
MangaAllInOneController::onFetchChaptersError
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UI after applying the filters.
|
||||
*/
|
||||
private fun refreshChapters() {
|
||||
chaptersRelay.call(chapters)
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the view filters to the list of chapters obtained from the database.
|
||||
* @param chapters the list of chapters from the database
|
||||
* @return an observable of the list of chapters filtered and sorted.
|
||||
*/
|
||||
private fun applyChapterFilters(chapters: List<ChapterItem>): Observable<List<ChapterItem>> {
|
||||
var observable = Observable.from(chapters).subscribeOn(Schedulers.io())
|
||||
private fun applyChapterFilters(chapterList: List<ChapterItem>): List<ChapterItem> {
|
||||
var chapters = chapterList
|
||||
if (onlyUnread()) {
|
||||
observable = observable.filter { !it.read }
|
||||
chapters = chapters.filter { !it.read }
|
||||
} else if (onlyRead()) {
|
||||
observable = observable.filter { it.read }
|
||||
chapters = chapters.filter { it.read }
|
||||
}
|
||||
if (onlyDownloaded()) {
|
||||
observable = observable.filter { it.isDownloaded || it.manga.source == LocalSource.ID }
|
||||
chapters = chapters.filter { it.isDownloaded || it.manga.source == LocalSource.ID }
|
||||
}
|
||||
if (onlyBookmarked()) {
|
||||
observable = observable.filter { it.bookmark }
|
||||
chapters = chapters.filter { it.bookmark }
|
||||
}
|
||||
val sortFunction: (Chapter, Chapter) -> Int = when (manga.sorting) {
|
||||
Manga.SORTING_SOURCE -> when (sortDescending()) {
|
||||
@ -457,9 +429,10 @@ class MangaAllInOnePresenter(
|
||||
true -> { c1, c2 -> c2.chapter_number.compareTo(c1.chapter_number) }
|
||||
false -> { c1, c2 -> c1.chapter_number.compareTo(c2.chapter_number) }
|
||||
}
|
||||
else -> throw NotImplementedError("Unimplemented sorting method")
|
||||
else -> { c1, c2 -> c1.source_order.compareTo(c2.source_order) }
|
||||
}
|
||||
return observable.toSortedList(sortFunction)
|
||||
chapters = chapters.sortedWith(Comparator(sortFunction))
|
||||
return chapters
|
||||
}
|
||||
|
||||
/**
|
||||
@ -478,7 +451,7 @@ class MangaAllInOnePresenter(
|
||||
|
||||
// Force UI update if downloaded filter active and download finished.
|
||||
if (onlyDownloaded() && download.status == Download.DOWNLOADED) {
|
||||
refreshChapters()
|
||||
updateChapters()
|
||||
}
|
||||
}
|
||||
|
||||
@ -541,7 +514,7 @@ class MangaAllInOnePresenter(
|
||||
fun deleteChapters(chapters: List<ChapterItem>) {
|
||||
Observable.just(chapters)
|
||||
.doOnNext { deleteChaptersInternal(chapters) }
|
||||
.doOnNext { if (onlyDownloaded()) refreshChapters() }
|
||||
.doOnNext { if (onlyDownloaded()) updateChapters() }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
@ -570,7 +543,7 @@ class MangaAllInOnePresenter(
|
||||
fun revertSortOrder() {
|
||||
manga.setChapterOrder(if (sortDescending()) Manga.SORT_ASC else Manga.SORT_DESC)
|
||||
db.updateFlags(manga).executeAsBlocking()
|
||||
refreshChapters()
|
||||
updateChapters()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -580,7 +553,7 @@ class MangaAllInOnePresenter(
|
||||
fun setUnreadFilter(onlyUnread: Boolean) {
|
||||
manga.readFilter = if (onlyUnread) Manga.SHOW_UNREAD else Manga.SHOW_ALL
|
||||
db.updateFlags(manga).executeAsBlocking()
|
||||
refreshChapters()
|
||||
updateChapters()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -590,7 +563,7 @@ class MangaAllInOnePresenter(
|
||||
fun setReadFilter(onlyRead: Boolean) {
|
||||
manga.readFilter = if (onlyRead) Manga.SHOW_READ else Manga.SHOW_ALL
|
||||
db.updateFlags(manga).executeAsBlocking()
|
||||
refreshChapters()
|
||||
updateChapters()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -600,7 +573,7 @@ class MangaAllInOnePresenter(
|
||||
fun setDownloadedFilter(onlyDownloaded: Boolean) {
|
||||
manga.downloadedFilter = if (onlyDownloaded) Manga.SHOW_DOWNLOADED else Manga.SHOW_ALL
|
||||
db.updateFlags(manga).executeAsBlocking()
|
||||
refreshChapters()
|
||||
updateChapters()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -610,7 +583,7 @@ class MangaAllInOnePresenter(
|
||||
fun setBookmarkedFilter(onlyBookmarked: Boolean) {
|
||||
manga.bookmarkedFilter = if (onlyBookmarked) Manga.SHOW_BOOKMARKED else Manga.SHOW_ALL
|
||||
db.updateFlags(manga).executeAsBlocking()
|
||||
refreshChapters()
|
||||
updateChapters()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -621,14 +594,14 @@ class MangaAllInOnePresenter(
|
||||
manga.downloadedFilter = Manga.SHOW_ALL
|
||||
manga.bookmarkedFilter = Manga.SHOW_ALL
|
||||
db.updateFlags(manga).executeAsBlocking()
|
||||
refreshChapters()
|
||||
updateChapters()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds manga to library
|
||||
*/
|
||||
fun addToLibrary() {
|
||||
mangaFavoriteRelay.call(true)
|
||||
setFavorite(true)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -647,7 +620,7 @@ class MangaAllInOnePresenter(
|
||||
fun setSorting(sort: Int) {
|
||||
manga.sorting = sort
|
||||
db.updateFlags(manga).executeAsBlocking()
|
||||
refreshChapters()
|
||||
updateChapters()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,6 +7,7 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.databinding.TrackControllerBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
||||
@ -17,7 +18,7 @@ import kotlinx.coroutines.flow.onEach
|
||||
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
|
||||
import timber.log.Timber
|
||||
|
||||
class TrackController :
|
||||
class TrackController(val fromAllInOne: Boolean = false, val manga: Manga? = null) :
|
||||
NucleusController<TrackControllerBinding, TrackPresenter>(),
|
||||
TrackAdapter.OnClickListener,
|
||||
SetTrackStatusDialog.Listener,
|
||||
@ -34,7 +35,13 @@ class TrackController :
|
||||
}
|
||||
|
||||
override fun createPresenter(): TrackPresenter {
|
||||
return TrackPresenter((parentController as MangaController).manga!!)
|
||||
return (
|
||||
if (fromAllInOne && manga != null) {
|
||||
TrackPresenter(manga)
|
||||
} else {
|
||||
TrackPresenter((parentController as MangaController).manga!!)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
@ -63,8 +70,10 @@ class TrackController :
|
||||
val atLeastOneLink = trackings.any { it.track != null }
|
||||
adapter?.items = trackings
|
||||
binding.swipeRefresh.isEnabled = atLeastOneLink
|
||||
if (!fromAllInOne) {
|
||||
(parentController as? MangaController)?.setTrackingIcon(atLeastOneLink)
|
||||
}
|
||||
}
|
||||
|
||||
fun onSearchResults(results: List<TrackSearch>) {
|
||||
getSearchDialog()?.onSearchResults(results)
|
||||
|
@ -204,16 +204,25 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/manga_source_label" />
|
||||
|
||||
<HorizontalScrollView
|
||||
android:id="@+id/actions_bar_scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:requiresFadingEdge="horizontal"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/manga_source" >
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/actions_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/manga_source">
|
||||
app:layout_constraintTop_toBottomOf="parent">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_favorite"
|
||||
@ -223,6 +232,17 @@
|
||||
android:text="@string/add_to_library"
|
||||
app:icon="@drawable/ic_favorite_border_24dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_tracking"
|
||||
style="@style/Theme.Widget.Button.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@string/track"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
app:icon="@drawable/ic_cloud_off_24dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_categories"
|
||||
style="@style/Theme.Widget.Button.Icon.Textless"
|
||||
@ -280,6 +300,8 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_summary_label"
|
||||
style="@style/TextAppearance.Regular.SubHeading"
|
||||
@ -290,7 +312,7 @@
|
||||
android:textIsSelectable="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/actions_bar" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/actions_bar_scroll_view" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_summary"
|
||||
|
@ -243,7 +243,7 @@
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/actions_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="16dp"
|
||||
@ -259,6 +259,17 @@
|
||||
android:text="@string/add_to_library"
|
||||
app:icon="@drawable/ic_favorite_border_24dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_tracking"
|
||||
style="@style/Theme.Widget.Button.Icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@string/track"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
app:icon="@drawable/ic_cloud_off_24dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_categories"
|
||||
style="@style/Theme.Widget.Button.Icon.Textless"
|
||||
|
Loading…
x
Reference in New Issue
Block a user