@ -1,36 +1,48 @@
package org.koitharu.kotatsu.core.exceptions.resolve
package org.koitharu.kotatsu.core.exceptions.resolve
import android.content.Context
import android.widget.Toast
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.StringRes
import androidx.annotation.StringRes
import androidx.collection. Array Map
import androidx.collection. MutableScatter Map
import androidx.fragment.app.Fragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.EntryPointAccessors
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.alternatives.ui.AlternativesActivity
import org.koitharu.kotatsu.alternatives.ui.AlternativesActivity
import org.koitharu.kotatsu.browser.BrowserActivity
import org.koitharu.kotatsu.browser.BrowserActivity
import org.koitharu.kotatsu.browser.cloudflare.CloudFlareActivity
import org.koitharu.kotatsu.browser.cloudflare.CloudFlareActivity
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException
import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BaseActivity.BaseActivityEntryPoint
import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog
import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog
import org.koitharu.kotatsu.core.util.TaggedActivityResult
import org.koitharu.kotatsu.core.util.TaggedActivityResult
import org.koitharu.kotatsu.core.util.ext.findActivity
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.exception.NotFoundException
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity
import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity
import java.security.cert.CertPathValidatorException
import javax.net.ssl.SSLException
import kotlin.coroutines.Continuation
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlin.coroutines.suspendCoroutine
class ExceptionResolver : ActivityResultCallback < TaggedActivityResult > {
class ExceptionResolver : ActivityResultCallback < TaggedActivityResult > {
private val continuations = Array Map< String , Continuation < Boolean > > ( 1 )
private val continuations = MutableScatter Map< String , Continuation < Boolean > > ( 1 )
private val activity : FragmentActivity ?
private val activity : FragmentActivity ?
private val fragment : Fragment ?
private val fragment : Fragment ?
private val sourceAuthContract : ActivityResultLauncher < MangaSource >
private val sourceAuthContract : ActivityResultLauncher < MangaSource >
private val cloudflareContract : ActivityResultLauncher < CloudFlareProtectedException >
private val cloudflareContract : ActivityResultLauncher < CloudFlareProtectedException >
val context : Context ?
get ( ) = activity ?: fragment ?. context
constructor ( activity : FragmentActivity ) {
constructor ( activity : FragmentActivity ) {
this . activity = activity
this . activity = activity
fragment = null
fragment = null
@ -56,6 +68,12 @@ class ExceptionResolver : ActivityResultCallback<TaggedActivityResult> {
suspend fun resolve ( e : Throwable ) : Boolean = when ( e ) {
suspend fun resolve ( e : Throwable ) : Boolean = when ( e ) {
is CloudFlareProtectedException -> resolveCF ( e )
is CloudFlareProtectedException -> resolveCF ( e )
is AuthRequiredException -> resolveAuthException ( e . source )
is AuthRequiredException -> resolveAuthException ( e . source )
is SSLException ,
is CertPathValidatorException -> {
showSslErrorDialog ( )
false
}
is NotFoundException -> {
is NotFoundException -> {
openInBrowser ( e . url )
openInBrowser ( e . url )
false
false
@ -80,13 +98,37 @@ class ExceptionResolver : ActivityResultCallback<TaggedActivityResult> {
}
}
private fun openInBrowser ( url : String ) {
private fun openInBrowser ( url : String ) {
val context = activity ?: fragment ?. activity ?: return
context ?. run {
context . startActivity ( BrowserActivity . newIntent ( context , url , null , null ) )
startActivity ( BrowserActivity . newIntent ( this , url , null , null ) )
}
}
}
private fun openAlternatives ( manga : Manga ) {
private fun openAlternatives ( manga : Manga ) {
val context = activity ?: fragment ?. activity ?: return
context ?. run {
context . startActivity ( AlternativesActivity . newIntent ( context , manga ) )
startActivity ( AlternativesActivity . newIntent ( this , manga ) )
}
}
private fun showSslErrorDialog ( ) {
val ctx = context ?: return
val settings = getAppSettings ( ctx )
if ( settings . isSSLBypassEnabled ) {
Toast . makeText ( ctx , R . string . operation _not _supported , Toast . LENGTH _SHORT ) . show ( )
return
}
MaterialAlertDialogBuilder ( ctx )
. setTitle ( R . string . ignore _ssl _errors )
. setMessage ( R . string . ignore _ssl _errors _summary )
. setPositiveButton ( R . string . apply ) { _ , _ ->
settings . isSSLBypassEnabled = true
Toast . makeText ( ctx , R . string . settings _apply _restart _required , Toast . LENGTH _SHORT ) . show ( )
ctx . findActivity ( ) ?. finishAffinity ( )
} . setNegativeButton ( android . R . string . cancel , null )
. show ( )
}
private fun getAppSettings ( context : Context ) : AppSettings {
return EntryPointAccessors . fromApplication < BaseActivityEntryPoint > ( context ) . settings
}
}
private fun getFragmentManager ( ) = checkNotNull ( fragment ?. childFragmentManager ?: activity ?. supportFragmentManager )
private fun getFragmentManager ( ) = checkNotNull ( fragment ?. childFragmentManager ?: activity ?. supportFragmentManager )
@ -99,6 +141,9 @@ class ExceptionResolver : ActivityResultCallback<TaggedActivityResult> {
is AuthRequiredException -> R . string . sign _in
is AuthRequiredException -> R . string . sign _in
is NotFoundException -> if ( e . url . isNotEmpty ( ) ) R . string . open _in _browser else 0
is NotFoundException -> if ( e . url . isNotEmpty ( ) ) R . string . open _in _browser else 0
is UnsupportedSourceException -> if ( e . manga != null ) R . string . alternatives else 0
is UnsupportedSourceException -> if ( e . manga != null ) R . string . alternatives else 0
is SSLException ,
is CertPathValidatorException -> R . string . fix
else -> 0
else -> 0
}
}