Update error details dialog
This commit is contained in:
@@ -86,7 +86,17 @@
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.settings.SettingsActivity"
|
||||
android:exported="true"
|
||||
android:label="@string/settings" />
|
||||
android:label="@string/settings">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="kotatsu" />
|
||||
<data android:host="about" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.koitharu.kotatsu.browser.BrowserActivity"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"
|
||||
@@ -145,6 +155,9 @@
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="kotatsu" />
|
||||
<data android:host="shikimori-auth" />
|
||||
<data android:host="anilist-auth" />
|
||||
<data android:host="mal-auth" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
@@ -6,7 +6,7 @@ import androidx.core.util.Consumer
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.MangaErrorDialog
|
||||
import org.koitharu.kotatsu.core.ui.ErrorDetailsDialog
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
|
||||
@@ -37,7 +37,7 @@ class DialogErrorObserver(
|
||||
val fm = fragmentManager
|
||||
if (fm != null) {
|
||||
dialogBuilder.setPositiveButton(R.string.details) { _, _ ->
|
||||
MangaErrorDialog.show(fm, error)
|
||||
ErrorDetailsDialog.show(fm, error, error.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
package org.koitharu.kotatsu.core.exceptions.resolve
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import androidx.activity.result.ActivityResultCallback
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.collection.ArrayMap
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import okhttp3.Headers
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.browser.BrowserActivity
|
||||
import org.koitharu.kotatsu.browser.cloudflare.CloudFlareDialog
|
||||
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
|
||||
import org.koitharu.kotatsu.core.ui.ErrorDetailsDialog
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.exception.NotFoundException
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity
|
||||
import org.koitharu.kotatsu.utils.TaggedActivityResult
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.utils.isSuccess
|
||||
import kotlin.coroutines.Continuation
|
||||
import kotlin.coroutines.resume
|
||||
@@ -48,6 +44,10 @@ class ExceptionResolver private constructor(
|
||||
continuations.remove(result.tag)?.resume(result.isSuccess)
|
||||
}
|
||||
|
||||
fun showDetails(e: Throwable, url: String?) {
|
||||
ErrorDetailsDialog.show(getFragmentManager(), e, url)
|
||||
}
|
||||
|
||||
suspend fun resolve(e: Throwable): Boolean = when (e) {
|
||||
is CloudFlareProtectedException -> resolveCF(e.url, e.headers)
|
||||
is AuthRequiredException -> resolveAuthException(e.source)
|
||||
@@ -100,21 +100,5 @@ class ExceptionResolver private constructor(
|
||||
}
|
||||
|
||||
fun canResolve(e: Throwable) = getResolveStringId(e) != 0
|
||||
|
||||
fun showDetails(context: Context, e: Throwable) {
|
||||
val stackTrace = e.stackTraceToString()
|
||||
val dialog = MaterialAlertDialogBuilder(context)
|
||||
.setTitle(e.getDisplayMessage(context.resources))
|
||||
.setMessage(stackTrace)
|
||||
.setPositiveButton(androidx.preference.R.string.copy) { _, _ ->
|
||||
val clipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
clipboardManager.setPrimaryClip(
|
||||
ClipData.newPlainText(context.getString(R.string.error), stackTrace),
|
||||
)
|
||||
}
|
||||
.setNegativeButton(R.string.close, null)
|
||||
.create()
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import androidx.core.util.Consumer
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.MangaErrorDialog
|
||||
import org.koitharu.kotatsu.core.ui.ErrorDetailsDialog
|
||||
import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||
@@ -38,7 +38,7 @@ class SnackbarErrorObserver(
|
||||
val fm = fragmentManager
|
||||
if (fm != null) {
|
||||
snackbar.setAction(R.string.details) {
|
||||
MangaErrorDialog.show(fm, error)
|
||||
ErrorDetailsDialog.show(fm, error, error.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.koitharu.kotatsu.core.ui
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.text.method.LinkMovementMethod
|
||||
import android.view.LayoutInflater
|
||||
@@ -12,15 +15,15 @@ import androidx.fragment.app.FragmentManager
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.base.ui.AlertDialogFragment
|
||||
import org.koitharu.kotatsu.databinding.DialogMangaErrorBinding
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.databinding.DialogErrorDetailsBinding
|
||||
import org.koitharu.kotatsu.utils.ext.isReportable
|
||||
import org.koitharu.kotatsu.utils.ext.report
|
||||
import org.koitharu.kotatsu.utils.ext.requireSerializable
|
||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||
|
||||
class MangaErrorDialog : AlertDialogFragment<DialogMangaErrorBinding>() {
|
||||
class ErrorDetailsDialog : AlertDialogFragment<DialogErrorDetailsBinding>() {
|
||||
|
||||
private lateinit var exception: ParseException
|
||||
private lateinit var exception: Throwable
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -28,8 +31,8 @@ class MangaErrorDialog : AlertDialogFragment<DialogMangaErrorBinding>() {
|
||||
exception = args.requireSerializable(ARG_ERROR)
|
||||
}
|
||||
|
||||
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): DialogMangaErrorBinding {
|
||||
return DialogMangaErrorBinding.inflate(inflater, container, false)
|
||||
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): DialogErrorDetailsBinding {
|
||||
return DialogErrorDetailsBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@@ -39,28 +42,45 @@ class MangaErrorDialog : AlertDialogFragment<DialogMangaErrorBinding>() {
|
||||
text = context.getString(
|
||||
R.string.manga_error_description_pattern,
|
||||
exception.message?.htmlEncode().orEmpty(),
|
||||
exception.url,
|
||||
arguments?.getString(ARG_URL),
|
||||
).parseAsHtml(HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||
return super.onBuildDialog(builder)
|
||||
val builder = super.onBuildDialog(builder)
|
||||
.setCancelable(true)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(R.string.report) { _, _ ->
|
||||
.setTitle(R.string.error_occurred)
|
||||
.setNeutralButton(androidx.preference.R.string.copy) { _, _ ->
|
||||
copyToClipboard()
|
||||
}
|
||||
if (exception.isReportable()) {
|
||||
builder.setPositiveButton(R.string.report) { _, _ ->
|
||||
dismiss()
|
||||
exception.report()
|
||||
}.setTitle(R.string.error_occurred)
|
||||
}
|
||||
}
|
||||
return builder
|
||||
}
|
||||
|
||||
private fun copyToClipboard() {
|
||||
val clipboardManager = context?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
|
||||
?: return
|
||||
clipboardManager.setPrimaryClip(
|
||||
ClipData.newPlainText(getString(R.string.error), exception.stackTraceToString()),
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "MangaErrorDialog"
|
||||
private const val TAG = "ErrorDetailsDialog"
|
||||
private const val ARG_ERROR = "error"
|
||||
private const val ARG_URL = "url"
|
||||
|
||||
fun show(fm: FragmentManager, error: ParseException) = MangaErrorDialog().withArgs(1) {
|
||||
fun show(fm: FragmentManager, error: Throwable, url: String?) = ErrorDetailsDialog().withArgs(2) {
|
||||
putSerializable(ARG_ERROR, error)
|
||||
putString(ARG_URL, url)
|
||||
}.show(fm, TAG)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.koitharu.kotatsu.reader.ui.pager
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.Observer
|
||||
@@ -60,9 +59,9 @@ class PageHolderDelegate(
|
||||
}
|
||||
}
|
||||
|
||||
fun showErrorDetails(context: Context) {
|
||||
fun showErrorDetails(url: String?) {
|
||||
val e = error ?: return
|
||||
ExceptionResolver.showDetails(context, e)
|
||||
exceptionResolver.showDetails(e, url)
|
||||
}
|
||||
|
||||
fun onAttachedToWindow() {
|
||||
|
||||
@@ -115,7 +115,7 @@ open class PageHolder(
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.button_retry -> delegate.retry(boundData?.toMangaPage() ?: return)
|
||||
R.id.button_error_details -> delegate.showErrorDetails(v.context)
|
||||
R.id.button_error_details -> delegate.showErrorDetails(boundData?.url)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ class WebtoonHolder(
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.button_retry -> delegate.retry(boundData?.toMangaPage() ?: return)
|
||||
R.id.button_error_details -> delegate.showErrorDetails(v.context)
|
||||
R.id.button_error_details -> delegate.showErrorDetails(boundData?.url)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,10 @@ import org.koitharu.kotatsu.base.ui.util.RecyclerViewOwner
|
||||
import org.koitharu.kotatsu.databinding.ActivitySettingsBinding
|
||||
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.settings.about.AboutSettingsFragment
|
||||
import org.koitharu.kotatsu.settings.sources.SourcesSettingsFragment
|
||||
import org.koitharu.kotatsu.settings.tracker.TrackerSettingsFragment
|
||||
import org.koitharu.kotatsu.utils.ext.getSerializableExtraCompat
|
||||
import org.koitharu.kotatsu.utils.ext.isScrolledToTop
|
||||
|
||||
@AndroidEntryPoint
|
||||
@@ -127,10 +129,17 @@ class SettingsActivity :
|
||||
ACTION_HISTORY -> HistorySettingsFragment()
|
||||
ACTION_TRACKER -> TrackerSettingsFragment()
|
||||
ACTION_SOURCE -> SourceSettingsFragment.newInstance(
|
||||
intent.getSerializableExtra(EXTRA_SOURCE) as? MangaSource ?: MangaSource.LOCAL,
|
||||
intent.getSerializableExtraCompat(EXTRA_SOURCE) as? MangaSource ?: MangaSource.LOCAL,
|
||||
)
|
||||
|
||||
ACTION_MANAGE_SOURCES -> SourcesSettingsFragment()
|
||||
Intent.ACTION_VIEW -> {
|
||||
when (intent.data?.host) {
|
||||
HOST_ABOUT -> AboutSettingsFragment()
|
||||
else -> SettingsHeadersFragment()
|
||||
}
|
||||
}
|
||||
|
||||
else -> SettingsHeadersFragment()
|
||||
}
|
||||
supportFragmentManager.commit {
|
||||
@@ -146,9 +155,9 @@ class SettingsActivity :
|
||||
private const val ACTION_TRACKER = "${BuildConfig.APPLICATION_ID}.action.MANAGE_TRACKER"
|
||||
private const val ACTION_HISTORY = "${BuildConfig.APPLICATION_ID}.action.MANAGE_HISTORY"
|
||||
private const val ACTION_SOURCE = "${BuildConfig.APPLICATION_ID}.action.MANAGE_SOURCE_SETTINGS"
|
||||
private const val ACTION_SHIKIMORI = "${BuildConfig.APPLICATION_ID}.action.MANAGE_SHIKIMORI_SETTINGS"
|
||||
private const val ACTION_MANAGE_SOURCES = "${BuildConfig.APPLICATION_ID}.action.MANAGE_SOURCES_LIST"
|
||||
private const val EXTRA_SOURCE = "source"
|
||||
private const val HOST_ABOUT = "about"
|
||||
|
||||
fun newIntent(context: Context) = Intent(context, SettingsActivity::class.java)
|
||||
|
||||
|
||||
@@ -21,6 +21,10 @@ inline fun <reified T : Parcelable> Intent.getParcelableExtraCompat(key: String)
|
||||
return getParcelableExtra(key) as T?
|
||||
}
|
||||
|
||||
inline fun <reified T : Serializable> Intent.getSerializableExtraCompat(key: String): T? {
|
||||
return getSerializableExtra(key) as T?
|
||||
}
|
||||
|
||||
inline fun <reified T : Serializable> Bundle.getSerializableCompat(key: String): T? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getSerializable(key, T::class.java)
|
||||
|
||||
@@ -377,7 +377,7 @@
|
||||
<string name="import_completed_hint">You can delete the original file from storage to save space</string>
|
||||
<string name="import_will_start_soon">Import will start soon</string>
|
||||
<string name="feed">Feed</string>
|
||||
<string name="manga_error_description_pattern">Error details:<br><tt>%1$s</tt><br><br>1. Try to <a href="%2$s">open manga in a web browser</a> to ensure it is available on its source<br>2. If it is available, send an error report to the developers.</string>
|
||||
<string name="manga_error_description_pattern">Error details:<br><tt>%1$s</tt><br><br>1. Try to <a href="%2$s">open manga in a web browser</a> to ensure it is available on its source<br>2. Make sure you are using the <a href="kotatsu://about">latest version of Kotatsu</a><br>3. If it is available, send an error report to the developers.</string>
|
||||
<string name="history_shortcuts">Show recent manga shortcuts</string>
|
||||
<string name="history_shortcuts_summary">Make recent manga available by long pressing on application icon</string>
|
||||
<string name="reader_control_ltr_summary">Tap on the right edge or pressing the right key always switches to the next page</string>
|
||||
|
||||
Reference in New Issue
Block a user