mirror of
https://github.com/mihonapp/mihon.git
synced 2025-11-15 05:27:28 +01:00
Manga cover updates (#3101)
* cover caching overhaul * add ui for removing custom cover * skip some loading work * minor cleanup * allow refresh library metadata to refresh local manga * rename metadata_date to cover_last_modified * rearrange removeMangaFromLibrary * change custom cover directory add setting for updating cover when refreshing library * remove toggle and explicit action for updating covers
This commit is contained in:
@@ -28,6 +28,7 @@ import eu.kanade.tachiyomi.ui.browse.source.filter.TextItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TextSectionItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateItem
|
||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@@ -279,7 +280,7 @@ open class BrowseSourcePresenter(
|
||||
fun changeMangaFavorite(manga: Manga) {
|
||||
manga.favorite = !manga.favorite
|
||||
if (!manga.favorite) {
|
||||
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||
manga.removeCovers(coverCache)
|
||||
}
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.ui.base.controller.DialogController
|
||||
|
||||
class ChangeMangaCoverDialog<T>(bundle: Bundle? = null) :
|
||||
DialogController(bundle) where T : Controller, T : ChangeMangaCoverDialog.Listener {
|
||||
|
||||
private lateinit var manga: Manga
|
||||
|
||||
constructor(target: T, manga: Manga) : this() {
|
||||
targetController = target
|
||||
this.manga = manga
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedViewState: Bundle?): Dialog {
|
||||
return MaterialDialog(activity!!)
|
||||
.title(R.string.action_edit_cover)
|
||||
.positiveButton(R.string.action_edit) {
|
||||
(targetController as? Listener)?.openMangaCoverPicker(manga)
|
||||
}
|
||||
.negativeButton(android.R.string.cancel)
|
||||
.neutralButton(R.string.action_delete) {
|
||||
(targetController as? Listener)?.deleteMangaCover(manga)
|
||||
}
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
fun deleteMangaCover(manga: Manga)
|
||||
|
||||
fun openMangaCoverPicker(manga: Manga)
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package eu.kanade.tachiyomi.ui.library
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.Menu
|
||||
@@ -22,6 +21,7 @@ import com.google.android.material.tabs.TabLayout
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import com.jakewharton.rxrelay.PublishRelay
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.models.Category
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.library.LibraryUpdateService
|
||||
@@ -37,7 +37,6 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
import eu.kanade.tachiyomi.util.system.toast
|
||||
import eu.kanade.tachiyomi.util.view.visible
|
||||
import java.io.IOException
|
||||
import kotlinx.android.synthetic.main.main_activity.tabs
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
@@ -51,11 +50,13 @@ import uy.kohesive.injekt.api.get
|
||||
|
||||
class LibraryController(
|
||||
bundle: Bundle? = null,
|
||||
private val preferences: PreferencesHelper = Injekt.get()
|
||||
private val preferences: PreferencesHelper = Injekt.get(),
|
||||
private val coverCache: CoverCache = Injekt.get()
|
||||
) : NucleusController<LibraryControllerBinding, LibraryPresenter>(bundle),
|
||||
RootController,
|
||||
TabbedController,
|
||||
ActionMode.Callback,
|
||||
ChangeMangaCoverDialog.Listener,
|
||||
ChangeMangaCategoriesDialog.Listener,
|
||||
DeleteLibraryMangasDialog.Listener {
|
||||
|
||||
@@ -424,10 +425,7 @@ class LibraryController(
|
||||
|
||||
private fun onActionItemClicked(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_edit_cover -> {
|
||||
changeSelectedCover()
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
R.id.action_edit_cover -> handleChangeCover()
|
||||
R.id.action_move_to_category -> showChangeMangaCategoriesDialog()
|
||||
R.id.action_delete -> showDeleteMangaDialog()
|
||||
R.id.action_select_all -> selectAllCategoryManga()
|
||||
@@ -486,6 +484,23 @@ class LibraryController(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleChangeCover() {
|
||||
val manga = selectedMangas.firstOrNull() ?: return
|
||||
|
||||
if (coverCache.getCustomCoverFile(manga).exists()) {
|
||||
showEditCoverDialog(manga)
|
||||
} else {
|
||||
openMangaCoverPicker(manga)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit custom cover for selected manga.
|
||||
*/
|
||||
private fun showEditCoverDialog(manga: Manga) {
|
||||
ChangeMangaCoverDialog(this, manga).showDialog(router)
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the selected manga to a list of categories.
|
||||
*/
|
||||
@@ -509,21 +524,7 @@ class LibraryController(
|
||||
DeleteLibraryMangasDialog(this, selectedMangas.toList()).showDialog(router)
|
||||
}
|
||||
|
||||
override fun updateCategoriesForMangas(mangas: List<Manga>, categories: List<Category>) {
|
||||
presenter.moveMangasToCategories(categories, mangas)
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
override fun deleteMangasFromLibrary(mangas: List<Manga>, deleteChapters: Boolean) {
|
||||
presenter.removeMangaFromLibrary(mangas, deleteChapters)
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the cover for the selected manga.
|
||||
*/
|
||||
private fun changeSelectedCover() {
|
||||
val manga = selectedMangas.firstOrNull() ?: return
|
||||
override fun openMangaCoverPicker(manga: Manga) {
|
||||
selectedCoverManga = manga
|
||||
|
||||
if (manga.favorite) {
|
||||
@@ -539,6 +540,23 @@ class LibraryController(
|
||||
} else {
|
||||
activity?.toast(R.string.notification_first_add_to_library)
|
||||
}
|
||||
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
override fun deleteMangaCover(manga: Manga) {
|
||||
presenter.deleteCustomCover(manga)
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
override fun updateCategoriesForMangas(mangas: List<Manga>, categories: List<Category>) {
|
||||
presenter.moveMangasToCategories(categories, mangas)
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
override fun deleteMangasFromLibrary(mangas: List<Manga>, deleteChapters: Boolean) {
|
||||
presenter.removeMangaFromLibrary(mangas, deleteChapters)
|
||||
destroyActionModeIfNeeded()
|
||||
}
|
||||
|
||||
private fun selectAllCategoryManga() {
|
||||
@@ -555,28 +573,25 @@ class LibraryController(
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == REQUEST_IMAGE_OPEN) {
|
||||
if (data == null || resultCode != Activity.RESULT_OK) return
|
||||
val dataUri = data?.data
|
||||
if (dataUri == null || resultCode != Activity.RESULT_OK) return
|
||||
val activity = activity ?: return
|
||||
val manga = selectedCoverManga ?: return
|
||||
|
||||
try {
|
||||
// Get the file's input stream from the incoming Intent
|
||||
activity.contentResolver.openInputStream(data.data ?: Uri.EMPTY).use {
|
||||
// Update cover to selected file, show error if something went wrong
|
||||
if (it != null && presenter.editCoverWithStream(it, manga)) {
|
||||
// TODO refresh cover
|
||||
} else {
|
||||
activity.toast(R.string.notification_cover_update_failed)
|
||||
}
|
||||
}
|
||||
} catch (error: IOException) {
|
||||
activity.toast(R.string.notification_cover_update_failed)
|
||||
Timber.e(error)
|
||||
}
|
||||
selectedCoverManga = null
|
||||
presenter.editCover(manga, activity, dataUri)
|
||||
}
|
||||
}
|
||||
|
||||
fun onSetCoverSuccess() {
|
||||
activity?.toast(R.string.cover_updated)
|
||||
}
|
||||
|
||||
fun onSetCoverError(error: Throwable) {
|
||||
activity?.toast(R.string.notification_cover_update_failed)
|
||||
Timber.e(error)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
/**
|
||||
* Key to change the cover of a manga in [onActivityResult].
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.util.isLocal
|
||||
import eu.kanade.tachiyomi.util.view.visibleIf
|
||||
import kotlinx.android.synthetic.main.source_grid_item.download_text
|
||||
import kotlinx.android.synthetic.main.source_grid_item.local_text
|
||||
@@ -48,7 +48,7 @@ class LibraryGridHolder(
|
||||
text = item.downloadCount.toString()
|
||||
}
|
||||
// set local visibility if its local manga
|
||||
local_text.visibleIf { item.manga.source == LocalSource.ID }
|
||||
local_text.visibleIf { item.manga.isLocal() }
|
||||
|
||||
// Update the cover.
|
||||
GlideApp.with(view.context).clear(thumbnail)
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
|
||||
import eu.kanade.tachiyomi.source.LocalSource
|
||||
import eu.kanade.tachiyomi.util.isLocal
|
||||
import eu.kanade.tachiyomi.util.view.visibleIf
|
||||
import kotlinx.android.synthetic.main.source_list_item.download_text
|
||||
import kotlinx.android.synthetic.main.source_list_item.local_text
|
||||
@@ -49,7 +49,7 @@ class LibraryListHolder(
|
||||
text = "${item.downloadCount}"
|
||||
}
|
||||
// show local text badge if local manga
|
||||
local_text.visibleIf { item.manga.source == LocalSource.ID }
|
||||
local_text.visibleIf { item.manga.isLocal() }
|
||||
|
||||
// Create thumbnail onclick to simulate long click
|
||||
thumbnail.setOnClickListener {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package eu.kanade.tachiyomi.ui.library
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import com.jakewharton.rxrelay.BehaviorRelay
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
@@ -14,11 +16,12 @@ import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.isLocal
|
||||
import eu.kanade.tachiyomi.util.lang.combineLatest
|
||||
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
||||
import java.util.ArrayList
|
||||
import java.util.Collections
|
||||
import java.util.Comparator
|
||||
@@ -128,7 +131,7 @@ class LibraryPresenter(
|
||||
// Filter when there are no downloads.
|
||||
if (filterDownloaded) {
|
||||
// Local manga are always downloaded
|
||||
if (item.manga.source == LocalSource.ID) {
|
||||
if (item.manga.isLocal()) {
|
||||
return@f true
|
||||
}
|
||||
// Don't bother with directory checking if download count has been set.
|
||||
@@ -318,16 +321,17 @@ class LibraryPresenter(
|
||||
* @param deleteChapters whether to also delete downloaded chapters.
|
||||
*/
|
||||
fun removeMangaFromLibrary(mangas: List<Manga>, deleteChapters: Boolean) {
|
||||
// Create a set of the list
|
||||
val mangaToDelete = mangas.distinctBy { it.id }
|
||||
mangaToDelete.forEach { it.favorite = false }
|
||||
|
||||
launchIO {
|
||||
val mangaToDelete = mangas.distinctBy { it.id }
|
||||
|
||||
mangaToDelete.forEach {
|
||||
it.favorite = false
|
||||
it.removeCovers(coverCache)
|
||||
}
|
||||
db.insertMangas(mangaToDelete).executeAsBlocking()
|
||||
|
||||
mangaToDelete.forEach { manga ->
|
||||
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||
if (deleteChapters) {
|
||||
if (deleteChapters) {
|
||||
mangaToDelete.forEach { manga ->
|
||||
val source = sourceManager.get(manga.source) as? HttpSource
|
||||
if (source != null) {
|
||||
downloadManager.deleteManga(manga, source)
|
||||
@@ -358,21 +362,42 @@ class LibraryPresenter(
|
||||
/**
|
||||
* Update cover with local file.
|
||||
*
|
||||
* @param inputStream the new cover.
|
||||
* @param manga the manga edited.
|
||||
* @return true if the cover is updated, false otherwise
|
||||
* @param context Context.
|
||||
* @param data uri of the cover resource.
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun editCoverWithStream(inputStream: InputStream, manga: Manga): Boolean {
|
||||
if (manga.source == LocalSource.ID) {
|
||||
LocalSource.updateCover(context, manga, inputStream)
|
||||
return true
|
||||
}
|
||||
fun editCover(manga: Manga, context: Context, data: Uri) {
|
||||
Observable
|
||||
.fromCallable {
|
||||
context.contentResolver.openInputStream(data)?.use {
|
||||
if (manga.isLocal()) {
|
||||
LocalSource.updateCover(context, manga, it)
|
||||
manga.updateCoverLastModified(db)
|
||||
} else if (manga.favorite) {
|
||||
coverCache.setCustomCoverToCache(manga, it)
|
||||
manga.updateCoverLastModified(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
{ view, _ -> view.onSetCoverSuccess() },
|
||||
{ view, e -> view.onSetCoverError(e) }
|
||||
)
|
||||
}
|
||||
|
||||
if (manga.thumbnail_url != null && manga.favorite) {
|
||||
coverCache.copyToCache(manga.thumbnail_url!!, inputStream)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
fun deleteCustomCover(manga: Manga) {
|
||||
Observable
|
||||
.fromCallable {
|
||||
coverCache.deleteCustomCover(manga)
|
||||
manga.updateCoverLastModified(db)
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribeFirst(
|
||||
{ view, _ -> view.onSetCoverSuccess() },
|
||||
{ view, e -> view.onSetCoverError(e) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
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.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.isLocal
|
||||
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
||||
import java.util.Date
|
||||
import rx.Observable
|
||||
@@ -189,7 +189,7 @@ class ChaptersPresenter(
|
||||
observable = observable.filter { it.read }
|
||||
}
|
||||
if (onlyDownloaded()) {
|
||||
observable = observable.filter { it.isDownloaded || it.manga.source == LocalSource.ID }
|
||||
observable = observable.filter { it.isDownloaded || it.manga.isLocal() }
|
||||
}
|
||||
if (onlyBookmarked()) {
|
||||
observable = observable.filter { it.bookmark }
|
||||
|
||||
@@ -67,8 +67,6 @@ class MangaInfoController(private val fromSource: Boolean = false) :
|
||||
|
||||
private var initialLoad: Boolean = true
|
||||
|
||||
private var thumbnailUrl: String? = null
|
||||
|
||||
override fun createPresenter(): MangaInfoPresenter {
|
||||
val ctrl = parentController as MangaController
|
||||
return MangaInfoPresenter(
|
||||
@@ -113,7 +111,7 @@ class MangaInfoController(private val fromSource: Boolean = false) :
|
||||
|
||||
// Set SwipeRefresh to refresh manga data.
|
||||
binding.swipeRefresh.refreshes()
|
||||
.onEach { fetchMangaFromSource() }
|
||||
.onEach { fetchMangaFromSource(manualFetch = true) }
|
||||
.launchIn(scope)
|
||||
|
||||
binding.mangaFullTitle.longClicks()
|
||||
@@ -241,23 +239,20 @@ class MangaInfoController(private val fromSource: Boolean = false) :
|
||||
setFavoriteButtonState(manga.favorite)
|
||||
|
||||
// Set cover if it wasn't already.
|
||||
if (binding.mangaCover.drawable == null || manga.thumbnail_url != thumbnailUrl) {
|
||||
thumbnailUrl = manga.thumbnail_url
|
||||
val mangaThumbnail = manga.toMangaThumbnail()
|
||||
val mangaThumbnail = manga.toMangaThumbnail()
|
||||
|
||||
GlideApp.with(view.context)
|
||||
.load(mangaThumbnail)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.centerCrop()
|
||||
.into(binding.mangaCover)
|
||||
|
||||
binding.backdrop?.let {
|
||||
GlideApp.with(view.context)
|
||||
.load(mangaThumbnail)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.centerCrop()
|
||||
.into(binding.mangaCover)
|
||||
|
||||
if (binding.backdrop != null) {
|
||||
GlideApp.with(view.context)
|
||||
.load(mangaThumbnail)
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.centerCrop()
|
||||
.into(binding.backdrop!!)
|
||||
}
|
||||
.into(it)
|
||||
}
|
||||
|
||||
// Manga info section
|
||||
@@ -422,10 +417,10 @@ class MangaInfoController(private val fromSource: Boolean = false) :
|
||||
/**
|
||||
* Start fetching manga information from source.
|
||||
*/
|
||||
private fun fetchMangaFromSource() {
|
||||
private fun fetchMangaFromSource(manualFetch: Boolean = false) {
|
||||
setRefreshing(true)
|
||||
// Call presenter and start fetching manga information
|
||||
presenter.fetchMangaFromSource()
|
||||
presenter.fetchMangaFromSource(manualFetch)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||
import eu.kanade.tachiyomi.util.lang.isNullOrUnsubscribed
|
||||
import eu.kanade.tachiyomi.util.prepUpdateCover
|
||||
import eu.kanade.tachiyomi.util.removeCovers
|
||||
import java.util.Date
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
@@ -36,11 +38,6 @@ class MangaInfoPresenter(
|
||||
private val coverCache: CoverCache = Injekt.get()
|
||||
) : BasePresenter<MangaInfoController>() {
|
||||
|
||||
/**
|
||||
* Subscription to send the manga to the view.
|
||||
*/
|
||||
private var viewMangaSubscription: Subscription? = null
|
||||
|
||||
/**
|
||||
* Subscription to update the manga from the source.
|
||||
*/
|
||||
@@ -48,7 +45,9 @@ class MangaInfoPresenter(
|
||||
|
||||
override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
sendMangaToView()
|
||||
|
||||
getMangaObservable()
|
||||
.subscribeLatestCache({ view, manga -> view.onNextManga(manga, source) })
|
||||
|
||||
// Update chapter count
|
||||
chapterCountRelay.observeOn(AndroidSchedulers.mainThread())
|
||||
@@ -64,22 +63,21 @@ class MangaInfoPresenter(
|
||||
.subscribeLatestCache(MangaInfoController::setLastUpdateDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the active manga to the view.
|
||||
*/
|
||||
fun sendMangaToView() {
|
||||
viewMangaSubscription?.let { remove(it) }
|
||||
viewMangaSubscription = Observable.just(manga)
|
||||
.subscribeLatestCache({ view, manga -> view.onNextManga(manga, source) })
|
||||
private fun getMangaObservable(): Observable<Manga> {
|
||||
return db.getManga(manga.url, manga.source).asRxObservable()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch manga information from source.
|
||||
*/
|
||||
fun fetchMangaFromSource() {
|
||||
fun fetchMangaFromSource(manualFetch: Boolean = false) {
|
||||
if (!fetchMangaSubscription.isNullOrUnsubscribed()) return
|
||||
fetchMangaSubscription = Observable.defer { source.fetchMangaDetails(manga) }
|
||||
.map { networkManga ->
|
||||
if (manualFetch || manga.thumbnail_url != networkManga.thumbnail_url) {
|
||||
manga.prepUpdateCover(coverCache)
|
||||
}
|
||||
manga.copyFrom(networkManga)
|
||||
manga.initialized = true
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
@@ -87,7 +85,6 @@ class MangaInfoPresenter(
|
||||
}
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnNext { sendMangaToView() }
|
||||
.subscribeFirst(
|
||||
{ view, _ ->
|
||||
view.onFetchMangaDone()
|
||||
@@ -104,10 +101,9 @@ class MangaInfoPresenter(
|
||||
fun toggleFavorite(): Boolean {
|
||||
manga.favorite = !manga.favorite
|
||||
if (!manga.favorite) {
|
||||
coverCache.deleteFromCache(manga.thumbnail_url)
|
||||
manga.removeCovers(coverCache)
|
||||
}
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
sendMangaToView()
|
||||
return manga.favorite
|
||||
}
|
||||
|
||||
|
||||
@@ -21,11 +21,13 @@ import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||
import eu.kanade.tachiyomi.util.isLocal
|
||||
import eu.kanade.tachiyomi.util.lang.byteSize
|
||||
import eu.kanade.tachiyomi.util.lang.launchIO
|
||||
import eu.kanade.tachiyomi.util.lang.takeBytes
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import eu.kanade.tachiyomi.util.updateCoverLastModified
|
||||
import java.io.File
|
||||
import java.util.Date
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -565,15 +567,16 @@ class ReaderPresenter(
|
||||
|
||||
Observable
|
||||
.fromCallable {
|
||||
if (manga.source == LocalSource.ID) {
|
||||
if (manga.isLocal()) {
|
||||
val context = Injekt.get<Application>()
|
||||
LocalSource.updateCover(context, manga, stream())
|
||||
manga.updateCoverLastModified(db)
|
||||
R.string.cover_updated
|
||||
SetAsCoverResult.Success
|
||||
} else {
|
||||
val thumbUrl = manga.thumbnail_url ?: throw Exception("Image url not found")
|
||||
if (manga.favorite) {
|
||||
coverCache.copyToCache(thumbUrl, stream())
|
||||
coverCache.setCustomCoverToCache(manga, stream())
|
||||
manga.updateCoverLastModified(db)
|
||||
SetAsCoverResult.Success
|
||||
} else {
|
||||
SetAsCoverResult.AddToLibraryFirst
|
||||
|
||||
@@ -64,12 +64,10 @@ class HistoryHolder(
|
||||
|
||||
// Set cover
|
||||
GlideApp.with(itemView.context).clear(cover)
|
||||
if (!manga.thumbnail_url.isNullOrEmpty()) {
|
||||
GlideApp.with(itemView.context)
|
||||
.load(manga.toMangaThumbnail())
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.centerCrop()
|
||||
.into(cover)
|
||||
}
|
||||
GlideApp.with(itemView.context)
|
||||
.load(manga.toMangaThumbnail())
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.centerCrop()
|
||||
.into(cover)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,13 +56,11 @@ class UpdatesHolder(private val view: View, private val adapter: UpdatesAdapter)
|
||||
|
||||
// Set cover
|
||||
GlideApp.with(itemView.context).clear(manga_cover)
|
||||
if (!item.manga.thumbnail_url.isNullOrEmpty()) {
|
||||
GlideApp.with(itemView.context)
|
||||
.load(item.manga.toMangaThumbnail())
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.circleCrop()
|
||||
.into(manga_cover)
|
||||
}
|
||||
GlideApp.with(itemView.context)
|
||||
.load(item.manga.toMangaThumbnail())
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.circleCrop()
|
||||
.into(manga_cover)
|
||||
|
||||
// Check if chapter is read and set correct color
|
||||
if (item.chapter.read) {
|
||||
|
||||
@@ -76,6 +76,11 @@ class SettingsAdvancedController : SettingsController() {
|
||||
ctrl.showDialog(router)
|
||||
}
|
||||
}
|
||||
preference {
|
||||
titleRes = R.string.pref_refresh_library_covers
|
||||
|
||||
onClick { LibraryUpdateService.start(context, target = Target.COVERS) }
|
||||
}
|
||||
preference {
|
||||
titleRes = R.string.pref_refresh_library_tracking
|
||||
summaryRes = R.string.pref_refresh_library_tracking_summary
|
||||
|
||||
Reference in New Issue
Block a user