@@ -0,0 +1,10 @@
|
||||
package org.koitharu.kotatsu.core.exceptions
|
||||
|
||||
import org.koitharu.kotatsu.details.ui.pager.EmptyMangaReason
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
|
||||
class EmptyMangaException(
|
||||
val reason: EmptyMangaReason?,
|
||||
val manga: Manga,
|
||||
cause: Throwable?
|
||||
) : IllegalStateException(cause)
|
||||
@@ -16,6 +16,7 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.browser.BrowserActivity
|
||||
import org.koitharu.kotatsu.browser.cloudflare.CloudFlareActivity
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.exceptions.EmptyMangaException
|
||||
import org.koitharu.kotatsu.core.exceptions.InteractiveActionRequiredException
|
||||
import org.koitharu.kotatsu.core.exceptions.ProxyConfigException
|
||||
import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException
|
||||
@@ -25,6 +26,7 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.ui.dialog.buildAlertDialog
|
||||
import org.koitharu.kotatsu.core.util.ext.isHttpUrl
|
||||
import org.koitharu.kotatsu.core.util.ext.restartApplication
|
||||
import org.koitharu.kotatsu.details.ui.pager.EmptyMangaReason
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.exception.NotFoundException
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
@@ -83,6 +85,16 @@ class ExceptionResolver private constructor(
|
||||
false
|
||||
}
|
||||
|
||||
is EmptyMangaException -> {
|
||||
when (e.reason) {
|
||||
EmptyMangaReason.NO_CHAPTERS -> openAlternatives(e.manga)
|
||||
EmptyMangaReason.LOADING_ERROR -> Unit
|
||||
EmptyMangaReason.RESTRICTED -> host.router.openBrowser(e.manga)
|
||||
else -> Unit
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
is UnsupportedSourceException -> {
|
||||
e.manga?.let { openAlternatives(it) }
|
||||
false
|
||||
@@ -229,6 +241,12 @@ class ExceptionResolver private constructor(
|
||||
|
||||
is InteractiveActionRequiredException -> R.string._continue
|
||||
|
||||
is EmptyMangaException -> when (e.reason) {
|
||||
EmptyMangaReason.RESTRICTED -> if (e.manga.publicUrl.isHttpUrl()) R.string.open_in_browser else 0
|
||||
EmptyMangaReason.NO_CHAPTERS -> R.string.alternatives
|
||||
else -> 0
|
||||
}
|
||||
|
||||
else -> 0
|
||||
}
|
||||
|
||||
|
||||
@@ -215,6 +215,12 @@ class AppRouter private constructor(
|
||||
startActivity(browserIntent(contextOrNull() ?: return, url, source, title))
|
||||
}
|
||||
|
||||
fun openBrowser(manga: Manga) = openBrowser(
|
||||
url = manga.publicUrl,
|
||||
source = manga.source,
|
||||
title = manga.title,
|
||||
)
|
||||
|
||||
fun openColorFilterConfig(manga: Manga, page: MangaPage) {
|
||||
startActivity(
|
||||
Intent(contextOrNull(), ColorFilterConfigActivity::class.java)
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.koitharu.kotatsu.core.exceptions.CaughtException
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareBlockedException
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.exceptions.EmptyHistoryException
|
||||
import org.koitharu.kotatsu.core.exceptions.EmptyMangaException
|
||||
import org.koitharu.kotatsu.core.exceptions.IncompatiblePluginException
|
||||
import org.koitharu.kotatsu.core.exceptions.InteractiveActionRequiredException
|
||||
import org.koitharu.kotatsu.core.exceptions.NoDataReceivedException
|
||||
@@ -103,6 +104,7 @@ private fun Throwable.getDisplayMessageOrNull(resources: Resources): String? = w
|
||||
is AccessDeniedException -> resources.getString(R.string.no_access_to_file)
|
||||
is NonFileUriException -> resources.getString(R.string.error_non_file_uri)
|
||||
is EmptyHistoryException -> resources.getString(R.string.history_is_empty)
|
||||
is EmptyMangaException -> reason?.let { resources.getString(it.msgResId) } ?: cause?.getDisplayMessage(resources)
|
||||
is ProxyConfigException -> resources.getString(R.string.invalid_proxy_configuration)
|
||||
is SyncApiException,
|
||||
is ContentUnavailableException -> message
|
||||
@@ -167,6 +169,8 @@ fun Throwable.getCauseUrl(): String? = when (this) {
|
||||
is CloudFlareProtectedException -> url
|
||||
is InteractiveActionRequiredException -> url
|
||||
is HttpStatusException -> url
|
||||
is UnsupportedSourceException -> manga?.publicUrl?.takeIf { it.isHttpUrl() }
|
||||
is EmptyMangaException -> manga.publicUrl.takeIf { it.isHttpUrl() }
|
||||
is HttpException -> (response.delegate as? Response)?.request?.url?.toString()
|
||||
else -> null
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.koitharu.kotatsu.core.ui.model.MangaOverride
|
||||
import org.koitharu.kotatsu.local.domain.model.LocalManga
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||
import org.koitharu.kotatsu.parsers.util.ifNullOrEmpty
|
||||
import org.koitharu.kotatsu.parsers.util.nullIfEmpty
|
||||
import org.koitharu.kotatsu.reader.data.filterChapters
|
||||
@@ -50,6 +51,9 @@ data class MangaDetails(
|
||||
.ifNullOrEmpty { localManga?.manga?.coverUrl }
|
||||
?.nullIfEmpty()
|
||||
|
||||
val isRestricted: Boolean
|
||||
get() = manga.state == MangaState.RESTRICTED
|
||||
|
||||
private val mergedManga by lazy {
|
||||
if (localManga == null) {
|
||||
// fast path
|
||||
|
||||
@@ -29,6 +29,7 @@ import kotlinx.coroutines.plus
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.bookmarks.domain.Bookmark
|
||||
import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository
|
||||
import org.koitharu.kotatsu.core.exceptions.EmptyMangaException
|
||||
import org.koitharu.kotatsu.core.model.getPreferredBranch
|
||||
import org.koitharu.kotatsu.core.nav.MangaIntent
|
||||
import org.koitharu.kotatsu.core.nav.ReaderIntent
|
||||
@@ -47,6 +48,7 @@ import org.koitharu.kotatsu.details.data.MangaDetails
|
||||
import org.koitharu.kotatsu.details.domain.DetailsInteractor
|
||||
import org.koitharu.kotatsu.details.domain.DetailsLoadUseCase
|
||||
import org.koitharu.kotatsu.details.ui.pager.ChaptersPagesViewModel
|
||||
import org.koitharu.kotatsu.details.ui.pager.EmptyMangaReason
|
||||
import org.koitharu.kotatsu.download.ui.worker.DownloadWorker
|
||||
import org.koitharu.kotatsu.history.data.HistoryRepository
|
||||
import org.koitharu.kotatsu.history.domain.HistoryUpdateUseCase
|
||||
@@ -405,9 +407,11 @@ class ReaderViewModel @Inject constructor(
|
||||
private fun loadImpl() {
|
||||
loadingJob = launchLoadingJob(Dispatchers.Default + EventExceptionHandler(onLoadingError)) {
|
||||
var exception: Exception? = null
|
||||
var loadedDetails: MangaDetails? = null
|
||||
try {
|
||||
detailsLoadUseCase(intent, force = false)
|
||||
.collect { details ->
|
||||
loadedDetails = details
|
||||
if (mangaDetails.value == null) {
|
||||
mangaDetails.value = details
|
||||
}
|
||||
@@ -452,9 +456,28 @@ class ReaderViewModel @Inject constructor(
|
||||
exception = e.mergeWith(exception)
|
||||
}
|
||||
if (readingState.value == null) {
|
||||
onLoadingError.call(
|
||||
exception ?: IllegalStateException("Unable to load manga. This should never happen. Please report"),
|
||||
val loadedManga = loadedDetails // for smart cast
|
||||
if (loadedManga != null) {
|
||||
mangaDetails.value = loadedManga.filterChapters(selectedBranch.value)
|
||||
}
|
||||
val loadingError = when {
|
||||
exception != null -> exception
|
||||
loadedManga == null || !loadedManga.isLoaded -> null
|
||||
loadedManga.isRestricted -> EmptyMangaException(
|
||||
EmptyMangaReason.RESTRICTED,
|
||||
loadedManga.toManga(),
|
||||
null,
|
||||
)
|
||||
|
||||
loadedManga.allChapters.isEmpty() -> EmptyMangaException(
|
||||
EmptyMangaReason.NO_CHAPTERS,
|
||||
loadedManga.toManga(),
|
||||
null,
|
||||
)
|
||||
|
||||
else -> null
|
||||
} ?: IllegalStateException("Unable to load manga. This should never happen. Please report")
|
||||
onLoadingError.call(loadingError)
|
||||
} else exception?.let { e ->
|
||||
// manga has been loaded but error occurred
|
||||
errorEvent.call(e)
|
||||
|
||||
Reference in New Issue
Block a user