Show dialog on manga loading error
This commit is contained in:
@@ -21,14 +21,14 @@ abstract class AlertDialogFragment<B : ViewBinding> : DialogFragment() {
|
|||||||
viewBinding = binding
|
viewBinding = binding
|
||||||
return MaterialAlertDialogBuilder(requireContext(), theme)
|
return MaterialAlertDialogBuilder(requireContext(), theme)
|
||||||
.setView(binding.root)
|
.setView(binding.root)
|
||||||
.also(::onBuildDialog)
|
.run(::onBuildDialog)
|
||||||
.create()
|
.create()
|
||||||
}
|
}
|
||||||
|
|
||||||
final override fun onCreateView(
|
final override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?,
|
||||||
) = viewBinding?.root
|
) = viewBinding?.root
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@@ -37,9 +37,9 @@ abstract class AlertDialogFragment<B : ViewBinding> : DialogFragment() {
|
|||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun onBuildDialog(builder: MaterialAlertDialogBuilder) = Unit
|
open fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder = builder
|
||||||
|
|
||||||
protected fun bindingOrNull(): B? = viewBinding
|
protected fun bindingOrNull(): B? = viewBinding
|
||||||
|
|
||||||
protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B
|
protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
|
|||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder) {
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||||
builder.setNegativeButton(android.R.string.cancel, null)
|
return super.onBuildDialog(builder).setNegativeButton(android.R.string.cancel, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.koitharu.kotatsu.core.ui
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.text.HtmlCompat
|
||||||
|
import androidx.core.text.htmlEncode
|
||||||
|
import androidx.core.text.parseAsHtml
|
||||||
|
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.core.model.parcelable.ParcelableManga
|
||||||
|
import org.koitharu.kotatsu.databinding.DialogMangaErrorBinding
|
||||||
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
|
import org.koitharu.kotatsu.utils.ext.report
|
||||||
|
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||||
|
|
||||||
|
class MangaErrorDialog : AlertDialogFragment<DialogMangaErrorBinding>() {
|
||||||
|
|
||||||
|
private lateinit var error: Throwable
|
||||||
|
private lateinit var manga: Manga
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
val args = requireArguments()
|
||||||
|
manga = requireNotNull(args.getParcelable<ParcelableManga>(ARG_MANGA)?.manga)
|
||||||
|
error = args.getSerializable(ARG_ERROR) as Throwable
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): DialogMangaErrorBinding {
|
||||||
|
return DialogMangaErrorBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
with(binding.textViewMessage) {
|
||||||
|
movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
text = context.getString(
|
||||||
|
R.string.manga_error_description_pattern,
|
||||||
|
this@MangaErrorDialog.error.message?.htmlEncode().orEmpty(),
|
||||||
|
manga.publicUrl,
|
||||||
|
).parseAsHtml(HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||||
|
return super.onBuildDialog(builder)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.report) { _, _ ->
|
||||||
|
dismiss()
|
||||||
|
error.report(TAG)
|
||||||
|
}.setTitle(R.string.error_occurred)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val TAG = "MangaErrorDialog"
|
||||||
|
private const val ARG_ERROR = "error"
|
||||||
|
private const val ARG_MANGA = "manga"
|
||||||
|
|
||||||
|
fun show(fm: FragmentManager, manga: Manga, error: Throwable) = MangaErrorDialog().withArgs(2) {
|
||||||
|
putParcelable(ARG_MANGA, ParcelableManga(manga, false))
|
||||||
|
putSerializable(ARG_ERROR, error)
|
||||||
|
}.show(fm, TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,6 @@ import com.google.android.material.badge.BadgeDrawable
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.base.domain.MangaIntent
|
import org.koitharu.kotatsu.base.domain.MangaIntent
|
||||||
@@ -27,6 +26,7 @@ import org.koitharu.kotatsu.base.ui.widgets.BottomSheetHeaderBar
|
|||||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||||
import org.koitharu.kotatsu.core.os.ShortcutsUpdater
|
import org.koitharu.kotatsu.core.os.ShortcutsUpdater
|
||||||
|
import org.koitharu.kotatsu.core.ui.MangaErrorDialog
|
||||||
import org.koitharu.kotatsu.databinding.ActivityDetailsBinding
|
import org.koitharu.kotatsu.databinding.ActivityDetailsBinding
|
||||||
import org.koitharu.kotatsu.details.ui.model.HistoryInfo
|
import org.koitharu.kotatsu.details.ui.model.HistoryInfo
|
||||||
import org.koitharu.kotatsu.download.ui.service.DownloadService
|
import org.koitharu.kotatsu.download.ui.service.DownloadService
|
||||||
@@ -36,6 +36,7 @@ import org.koitharu.kotatsu.parsers.model.Manga
|
|||||||
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||||
import org.koitharu.kotatsu.utils.ext.*
|
import org.koitharu.kotatsu.utils.ext.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class DetailsActivity :
|
class DetailsActivity :
|
||||||
@@ -172,11 +173,12 @@ class DetailsActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onError(e: Throwable) {
|
private fun onError(e: Throwable) {
|
||||||
|
val manga = viewModel.manga.value
|
||||||
when {
|
when {
|
||||||
ExceptionResolver.canResolve(e) -> {
|
ExceptionResolver.canResolve(e) -> {
|
||||||
resolveError(e)
|
resolveError(e)
|
||||||
}
|
}
|
||||||
viewModel.manga.value == null -> {
|
manga == null -> {
|
||||||
Toast.makeText(this, e.getDisplayMessage(resources), Toast.LENGTH_LONG).show()
|
Toast.makeText(this, e.getDisplayMessage(resources), Toast.LENGTH_LONG).show()
|
||||||
finishAfterTransition()
|
finishAfterTransition()
|
||||||
}
|
}
|
||||||
@@ -192,8 +194,8 @@ class DetailsActivity :
|
|||||||
)
|
)
|
||||||
snackbar.anchorView = binding.headerChapters
|
snackbar.anchorView = binding.headerChapters
|
||||||
if (e.isReportable()) {
|
if (e.isReportable()) {
|
||||||
snackbar.setAction(R.string.report) {
|
snackbar.setAction(R.string.details) {
|
||||||
e.report("DetailsActivity::onError")
|
MangaErrorDialog.show(supportFragmentManager, manga, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
snackbar.show()
|
snackbar.show()
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import androidx.fragment.app.FragmentManager
|
|||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.slider.Slider
|
import com.google.android.material.slider.Slider
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import javax.inject.Inject
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.base.ui.AlertDialogFragment
|
import org.koitharu.kotatsu.base.ui.AlertDialogFragment
|
||||||
import org.koitharu.kotatsu.base.ui.widgets.CheckableButtonGroup
|
import org.koitharu.kotatsu.base.ui.widgets.CheckableButtonGroup
|
||||||
@@ -17,7 +18,6 @@ import org.koitharu.kotatsu.core.prefs.ListMode
|
|||||||
import org.koitharu.kotatsu.databinding.DialogListModeBinding
|
import org.koitharu.kotatsu.databinding.DialogListModeBinding
|
||||||
import org.koitharu.kotatsu.utils.ext.setValueRounded
|
import org.koitharu.kotatsu.utils.ext.setValueRounded
|
||||||
import org.koitharu.kotatsu.utils.progress.IntPercentLabelFormatter
|
import org.koitharu.kotatsu.utils.progress.IntPercentLabelFormatter
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ListModeSelectDialog :
|
class ListModeSelectDialog :
|
||||||
@@ -33,8 +33,9 @@ class ListModeSelectDialog :
|
|||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
) = DialogListModeBinding.inflate(inflater, container, false)
|
) = DialogListModeBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder) {
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||||
builder.setTitle(R.string.list_mode)
|
return super.onBuildDialog(builder)
|
||||||
|
.setTitle(R.string.list_mode)
|
||||||
.setPositiveButton(R.string.done, null)
|
.setPositiveButton(R.string.done, null)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,8 +27,9 @@ class ImportDialogFragment : AlertDialogFragment<DialogImportBinding>(), View.On
|
|||||||
return DialogImportBinding.inflate(inflater, container, false)
|
return DialogImportBinding.inflate(inflater, container, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder) {
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||||
builder.setTitle(R.string._import)
|
return super.onBuildDialog(builder)
|
||||||
|
.setTitle(R.string._import)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,15 @@ import org.koitharu.kotatsu.databinding.DialogReaderConfigBinding
|
|||||||
import org.koitharu.kotatsu.utils.ext.withArgs
|
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||||
|
|
||||||
@Deprecated("Not in use")
|
@Deprecated("Not in use")
|
||||||
class ReaderConfigDialog : AlertDialogFragment<DialogReaderConfigBinding>(),
|
class ReaderConfigDialog :
|
||||||
|
AlertDialogFragment<DialogReaderConfigBinding>(),
|
||||||
CheckableButtonGroup.OnCheckedChangeListener {
|
CheckableButtonGroup.OnCheckedChangeListener {
|
||||||
|
|
||||||
private lateinit var mode: ReaderMode
|
private lateinit var mode: ReaderMode
|
||||||
|
|
||||||
override fun onInflateView(
|
override fun onInflateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?
|
container: ViewGroup?,
|
||||||
) = DialogReaderConfigBinding.inflate(inflater, container, false)
|
) = DialogReaderConfigBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -32,8 +33,9 @@ class ReaderConfigDialog : AlertDialogFragment<DialogReaderConfigBinding>(),
|
|||||||
?: ReaderMode.STANDARD
|
?: ReaderMode.STANDARD
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder) {
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||||
builder.setTitle(R.string.read_mode)
|
return super.onBuildDialog(builder)
|
||||||
|
.setTitle(R.string.read_mode)
|
||||||
.setPositiveButton(R.string.done, null)
|
.setPositiveButton(R.string.done, null)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
}
|
}
|
||||||
@@ -48,8 +50,10 @@ class ReaderConfigDialog : AlertDialogFragment<DialogReaderConfigBinding>(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDismiss(dialog: DialogInterface) {
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
((parentFragment as? Callback)
|
(
|
||||||
?: (activity as? Callback))?.onReaderModeChanged(mode)
|
(parentFragment as? Callback)
|
||||||
|
?: (activity as? Callback)
|
||||||
|
)?.onReaderModeChanged(mode)
|
||||||
super.onDismiss(dialog)
|
super.onDismiss(dialog)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,8 +51,9 @@ class BackupDialogFragment : AlertDialogFragment<DialogProgressBinding>() {
|
|||||||
viewModel.onError.observe(viewLifecycleOwner, this::onError)
|
viewModel.onError.observe(viewLifecycleOwner, this::onError)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder) {
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||||
builder.setCancelable(false)
|
return super.onBuildDialog(builder)
|
||||||
|
.setCancelable(false)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,9 @@ class RestoreDialogFragment : AlertDialogFragment<DialogProgressBinding>() {
|
|||||||
viewModel.onError.observe(viewLifecycleOwner, this::onError)
|
viewModel.onError.observe(viewLifecycleOwner, this::onError)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder) {
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||||
builder.setCancelable(false)
|
return super.onBuildDialog(builder)
|
||||||
|
.setCancelable(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onError(e: Throwable) {
|
private fun onError(e: Throwable) {
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ class NewSourcesDialogFragment :
|
|||||||
viewModel.sources.observe(viewLifecycleOwner) { adapter.items = it }
|
viewModel.sources.observe(viewLifecycleOwner) { adapter.items = it }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder) {
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||||
builder
|
return super.onBuildDialog(builder)
|
||||||
.setPositiveButton(R.string.done, this)
|
.setPositiveButton(R.string.done, this)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setTitle(R.string.remote_sources)
|
.setTitle(R.string.remote_sources)
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ class OnboardDialogFragment :
|
|||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
) = DialogOnboardBinding.inflate(inflater, container, false)
|
) = DialogOnboardBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder) {
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
||||||
builder
|
super.onBuildDialog(builder)
|
||||||
.setPositiveButton(R.string.done, this)
|
.setPositiveButton(R.string.done, this)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
if (isWelcome) {
|
if (isWelcome) {
|
||||||
@@ -50,6 +50,7 @@ class OnboardDialogFragment :
|
|||||||
.setTitle(R.string.remote_sources)
|
.setTitle(R.string.remote_sources)
|
||||||
.setNegativeButton(android.R.string.cancel, this)
|
.setNegativeButton(android.R.string.cancel, this)
|
||||||
}
|
}
|
||||||
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
|||||||
25
app/src/main/res/layout/dialog_manga_error.xml
Normal file
25
app/src/main/res/layout/dialog_manga_error.xml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingHorizontal="@dimen/margin_normal"
|
||||||
|
android:paddingTop="@dimen/margin_normal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_message"
|
||||||
|
style="@style/MaterialAlertDialog.Material3.Body.Text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:linksClickable="true"
|
||||||
|
tools:text="@tools:sample/lorem[20]" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
@@ -376,4 +376,5 @@
|
|||||||
<string name="import_completed_hint">You can delete the original file from storage to save space</string>
|
<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="import_will_start_soon">Import will start soon</string>
|
||||||
<string name="feed">Feed</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>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user