diff --git a/app/src/main/java/org/koitharu/kotatsu/base/ui/AlertDialogFragment.kt b/app/src/main/java/org/koitharu/kotatsu/base/ui/AlertDialogFragment.kt index e1e328c8f..8866cc068 100644 --- a/app/src/main/java/org/koitharu/kotatsu/base/ui/AlertDialogFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/base/ui/AlertDialogFragment.kt @@ -21,14 +21,14 @@ abstract class AlertDialogFragment : DialogFragment() { viewBinding = binding return MaterialAlertDialogBuilder(requireContext(), theme) .setView(binding.root) - .also(::onBuildDialog) + .run(::onBuildDialog) .create() } final override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ) = viewBinding?.root @CallSuper @@ -37,9 +37,9 @@ abstract class AlertDialogFragment : DialogFragment() { super.onDestroyView() } - open fun onBuildDialog(builder: MaterialAlertDialogBuilder) = Unit + open fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder = builder protected fun bindingOrNull(): B? = viewBinding protected abstract fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): B -} \ No newline at end of file +} diff --git a/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt b/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt index 683d8abb0..cc9e5fb33 100644 --- a/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/browser/cloudflare/CloudFlareDialog.kt @@ -58,8 +58,8 @@ class CloudFlareDialog : AlertDialogFragment(), Cloud super.onDestroyView() } - override fun onBuildDialog(builder: MaterialAlertDialogBuilder) { - builder.setNegativeButton(android.R.string.cancel, null) + override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { + return super.onBuildDialog(builder).setNegativeButton(android.R.string.cancel, null) } override fun onResume() { diff --git a/app/src/main/java/org/koitharu/kotatsu/core/ui/MangaErrorDialog.kt b/app/src/main/java/org/koitharu/kotatsu/core/ui/MangaErrorDialog.kt new file mode 100644 index 000000000..532816f89 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/core/ui/MangaErrorDialog.kt @@ -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() { + + 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(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) + } +} diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt index 25b43c7c2..ac747eb9b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsActivity.kt @@ -18,7 +18,6 @@ import com.google.android.material.badge.BadgeDrawable import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import dagger.hilt.android.AndroidEntryPoint -import javax.inject.Inject import kotlinx.coroutines.launch import org.koitharu.kotatsu.R 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.model.parcelable.ParcelableManga import org.koitharu.kotatsu.core.os.ShortcutsUpdater +import org.koitharu.kotatsu.core.ui.MangaErrorDialog import org.koitharu.kotatsu.databinding.ActivityDetailsBinding import org.koitharu.kotatsu.details.ui.model.HistoryInfo 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.ReaderState import org.koitharu.kotatsu.utils.ext.* +import javax.inject.Inject @AndroidEntryPoint class DetailsActivity : @@ -172,11 +173,12 @@ class DetailsActivity : } private fun onError(e: Throwable) { + val manga = viewModel.manga.value when { ExceptionResolver.canResolve(e) -> { resolveError(e) } - viewModel.manga.value == null -> { + manga == null -> { Toast.makeText(this, e.getDisplayMessage(resources), Toast.LENGTH_LONG).show() finishAfterTransition() } @@ -192,8 +194,8 @@ class DetailsActivity : ) snackbar.anchorView = binding.headerChapters if (e.isReportable()) { - snackbar.setAction(R.string.report) { - e.report("DetailsActivity::onError") + snackbar.setAction(R.string.details) { + MangaErrorDialog.show(supportFragmentManager, manga, e) } } snackbar.show() diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/ListModeSelectDialog.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/ListModeSelectDialog.kt index 1c988732a..3728c57b2 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/ListModeSelectDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/ListModeSelectDialog.kt @@ -9,6 +9,7 @@ import androidx.fragment.app.FragmentManager import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.slider.Slider import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject import org.koitharu.kotatsu.R import org.koitharu.kotatsu.base.ui.AlertDialogFragment 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.utils.ext.setValueRounded import org.koitharu.kotatsu.utils.progress.IntPercentLabelFormatter -import javax.inject.Inject @AndroidEntryPoint class ListModeSelectDialog : @@ -33,8 +33,9 @@ class ListModeSelectDialog : container: ViewGroup?, ) = DialogListModeBinding.inflate(inflater, container, false) - override fun onBuildDialog(builder: MaterialAlertDialogBuilder) { - builder.setTitle(R.string.list_mode) + override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { + return super.onBuildDialog(builder) + .setTitle(R.string.list_mode) .setPositiveButton(R.string.done, null) .setCancelable(true) } diff --git a/app/src/main/java/org/koitharu/kotatsu/local/ui/ImportDialogFragment.kt b/app/src/main/java/org/koitharu/kotatsu/local/ui/ImportDialogFragment.kt index 000e57c14..5cd6cf85b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/local/ui/ImportDialogFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/local/ui/ImportDialogFragment.kt @@ -27,8 +27,9 @@ class ImportDialogFragment : AlertDialogFragment(), View.On return DialogImportBinding.inflate(inflater, container, false) } - override fun onBuildDialog(builder: MaterialAlertDialogBuilder) { - builder.setTitle(R.string._import) + override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { + return super.onBuildDialog(builder) + .setTitle(R.string._import) .setNegativeButton(android.R.string.cancel, null) .setCancelable(true) } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderConfigDialog.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderConfigDialog.kt index 916b0ee5f..890c9074b 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderConfigDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/ReaderConfigDialog.kt @@ -15,14 +15,15 @@ import org.koitharu.kotatsu.databinding.DialogReaderConfigBinding import org.koitharu.kotatsu.utils.ext.withArgs @Deprecated("Not in use") -class ReaderConfigDialog : AlertDialogFragment(), +class ReaderConfigDialog : + AlertDialogFragment(), CheckableButtonGroup.OnCheckedChangeListener { private lateinit var mode: ReaderMode override fun onInflateView( inflater: LayoutInflater, - container: ViewGroup? + container: ViewGroup?, ) = DialogReaderConfigBinding.inflate(inflater, container, false) override fun onCreate(savedInstanceState: Bundle?) { @@ -32,8 +33,9 @@ class ReaderConfigDialog : AlertDialogFragment(), ?: ReaderMode.STANDARD } - override fun onBuildDialog(builder: MaterialAlertDialogBuilder) { - builder.setTitle(R.string.read_mode) + override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { + return super.onBuildDialog(builder) + .setTitle(R.string.read_mode) .setPositiveButton(R.string.done, null) .setCancelable(true) } @@ -48,8 +50,10 @@ class ReaderConfigDialog : AlertDialogFragment(), } override fun onDismiss(dialog: DialogInterface) { - ((parentFragment as? Callback) - ?: (activity as? Callback))?.onReaderModeChanged(mode) + ( + (parentFragment as? Callback) + ?: (activity as? Callback) + )?.onReaderModeChanged(mode) super.onDismiss(dialog) } diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt index 65d0a0d47..825575ad9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/backup/BackupDialogFragment.kt @@ -51,8 +51,9 @@ class BackupDialogFragment : AlertDialogFragment() { viewModel.onError.observe(viewLifecycleOwner, this::onError) } - override fun onBuildDialog(builder: MaterialAlertDialogBuilder) { - builder.setCancelable(false) + override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { + return super.onBuildDialog(builder) + .setCancelable(false) .setNegativeButton(android.R.string.cancel, null) } diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt index 5af836d4b..68edfe874 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/backup/RestoreDialogFragment.kt @@ -44,8 +44,9 @@ class RestoreDialogFragment : AlertDialogFragment() { viewModel.onError.observe(viewLifecycleOwner, this::onError) } - override fun onBuildDialog(builder: MaterialAlertDialogBuilder) { - builder.setCancelable(false) + override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { + return super.onBuildDialog(builder) + .setCancelable(false) } private fun onError(e: Throwable) { diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/newsources/NewSourcesDialogFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/newsources/NewSourcesDialogFragment.kt index c500a8527..ac855f1e1 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/newsources/NewSourcesDialogFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/newsources/NewSourcesDialogFragment.kt @@ -43,8 +43,8 @@ class NewSourcesDialogFragment : viewModel.sources.observe(viewLifecycleOwner) { adapter.items = it } } - override fun onBuildDialog(builder: MaterialAlertDialogBuilder) { - builder + override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { + return super.onBuildDialog(builder) .setPositiveButton(R.string.done, this) .setCancelable(true) .setTitle(R.string.remote_sources) diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt index 6cb8eb25e..74620b78f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt @@ -39,8 +39,8 @@ class OnboardDialogFragment : container: ViewGroup?, ) = DialogOnboardBinding.inflate(inflater, container, false) - override fun onBuildDialog(builder: MaterialAlertDialogBuilder) { - builder + override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder { + super.onBuildDialog(builder) .setPositiveButton(R.string.done, this) .setCancelable(true) if (isWelcome) { @@ -50,6 +50,7 @@ class OnboardDialogFragment : .setTitle(R.string.remote_sources) .setNegativeButton(android.R.string.cancel, this) } + return builder } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/app/src/main/res/layout/dialog_manga_error.xml b/app/src/main/res/layout/dialog_manga_error.xml new file mode 100644 index 000000000..be84d7bbc --- /dev/null +++ b/app/src/main/res/layout/dialog_manga_error.xml @@ -0,0 +1,25 @@ + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 595f2074f..2a9515dcc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -376,4 +376,5 @@ You can delete the original file from storage to save space Import will start soon Feed + 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.