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:
Jobobby04 2020-05-16 17:53:02 -04:00
parent e6f5ea172a
commit 4a64bb250d
5 changed files with 257 additions and 255 deletions

View File

@ -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)
}

View File

@ -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,130 +87,136 @@ 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) })
if (manga.isLocal()) {
controller.setRefreshing(true)
fetchMangaFromSource()
} else if (!manga.initialized) {
controller.setRefreshing(true)
fetchMangaFromSource()
} else {
updateManga()
}
// 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() }
}
.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
)
// 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
) {
// Check for gallery in library and accept manga with lowest id
// Find chapters sharing same root
add(
updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters)
.subscribeOn(Schedulers.io())
.subscribe { (acceptedChain, _) ->
// Redirect if we are not the accepted root
if (manga.id != acceptedChain.manga.id) {
// Update if any of our chapters are not in accepted manga's chapters
val ourChapterUrls = chapters.map { it.url }.toSet()
val acceptedChapterUrls = acceptedChain.chapters.map { it.url }.toSet()
val update = (ourChapterUrls - acceptedChapterUrls).isNotEmpty()
redirectUserRelay.call(
ChaptersPresenter.EXHRedirect(
acceptedChain.manga,
update
)
)
}
}
)
}
// EXH <--
}
.subscribe { chaptersRelay.call(it) }
)
// Update favorite status
mangaFavoriteRelay.observeOn(AndroidSchedulers.mainThread())
.subscribe { setFavorite(it) }
.apply { add(this) }
// update last update date
lastUpdateRelay.observeOn(AndroidSchedulers.mainThread())
.subscribeLatestCache(MangaAllInOneController::setLastUpdateDate)
// Listen for download status changes
observeDownloads()
}
private fun getMangaObservable(): Observable<Manga> {
return db.getManga(manga.url, manga.source).asRxObservable()
.observeOn(AndroidSchedulers.mainThread())
private fun updateChapters() {
val chapters = db.getChapters(manga).executeAsBlocking().map { it.toModel() }
// Find downloaded chapters
setDownloadedChapters(chapters)
// EXH -->
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(
updateHelper.findAcceptedRootAndDiscardOthers(manga.source, chapters)
.subscribeOn(Schedulers.io())
.subscribe { (acceptedChain, _) ->
// Redirect if we are not the accepted root
if (manga.id != acceptedChain.manga.id) {
// Update if any of our chapters are not in accepted manga's chapters
val ourChapterUrls = chapters.map { it.url }.toSet()
val acceptedChapterUrls = acceptedChain.chapters.map { it.url }.toSet()
val update = (ourChapterUrls - acceptedChapterUrls).isNotEmpty()
redirectUserRelay.call(
ChaptersPresenter.EXHRedirect(
acceptedChain.manga,
update
)
)
}
}
)
}
// EXH <--
this.chapters = applyChapterFilters(chapters)
}
private fun updateChapterInfo() {
scope.launch(Dispatchers.IO) {
val lastUpdateDate = Date(
chapters.maxBy { it.date_upload }?.date_upload ?: 0
)
val chapterCount = chapters.maxBy { it.chapter_number }?.chapter_number ?: 0f
withContext(Dispatchers.Main) {
// set chapter count
controller.setChapterCount(chapterCount)
// update last update date
controller.setLastUpdateDate(lastUpdateDate)
}
}
}
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 ->
manga.prepUpdateCover(coverCache, networkManga, manualFetch)
manga.copyFrom(networkManga)
manga.initialized = true
db.insertManga(manga).executeAsBlocking()
manga
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()
}
}
.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()
}
/**

View File

@ -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,7 +70,9 @@ class TrackController :
val atLeastOneLink = trackings.any { it.track != null }
adapter?.items = trackings
binding.swipeRefresh.isEnabled = atLeastOneLink
(parentController as? MangaController)?.setTrackingIcon(atLeastOneLink)
if (!fromAllInOne) {
(parentController as? MangaController)?.setTrackingIcon(atLeastOneLink)
}
}
fun onSearchResults(results: List<TrackSearch>) {

View File

@ -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"

View File

@ -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"