From b036a8ed942114d2cb385812445493a6b82985cb Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 4 Nov 2024 10:02:08 +0200 Subject: [PATCH] Fixes batch --- .../org/koitharu/kotatsu/StrictModeNotifier.kt | 15 ++++++++++++--- app/src/debug/res/drawable-anydpi-v24/ic_bug.xml | 15 +++++++++++++++ app/src/debug/res/drawable-hdpi/ic_bug.png | Bin 0 -> 417 bytes app/src/debug/res/drawable-mdpi/ic_bug.png | Bin 0 -> 308 bytes app/src/debug/res/drawable-xhdpi/ic_bug.png | Bin 0 -> 480 bytes app/src/debug/res/drawable-xxhdpi/ic_bug.png | Bin 0 -> 792 bytes .../browser/cloudflare/CaptchaNotifier.kt | 6 +++--- .../exceptions/resolve/DialogErrorObserver.kt | 3 ++- .../exceptions/resolve/SnackbarErrorObserver.kt | 3 ++- .../koitharu/kotatsu/core/io/NullOutputStream.kt | 13 +++++++++++++ .../koitharu/kotatsu/core/util/ShareHelper.kt | 13 ++++++------- .../org/koitharu/kotatsu/core/util/ext/Bundle.kt | 4 ++++ .../koitharu/kotatsu/core/util/ext/Throwable.kt | 8 ++++++++ .../kotatsu/details/ui/DetailsErrorObserver.kt | 3 ++- .../reader/ui/pager/standard/PageHolder.kt | 2 ++ .../reader/ui/pager/webtoon/WebtoonHolder.kt | 2 ++ app/src/main/res/menu/opt_local.xml | 8 +++++++- 17 files changed, 78 insertions(+), 17 deletions(-) create mode 100644 app/src/debug/res/drawable-anydpi-v24/ic_bug.xml create mode 100644 app/src/debug/res/drawable-hdpi/ic_bug.png create mode 100644 app/src/debug/res/drawable-mdpi/ic_bug.png create mode 100644 app/src/debug/res/drawable-xhdpi/ic_bug.png create mode 100644 app/src/debug/res/drawable-xxhdpi/ic_bug.png create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/core/io/NullOutputStream.kt diff --git a/app/src/debug/kotlin/org/koitharu/kotatsu/StrictModeNotifier.kt b/app/src/debug/kotlin/org/koitharu/kotatsu/StrictModeNotifier.kt index 8847cb601..058e53c09 100644 --- a/app/src/debug/kotlin/org/koitharu/kotatsu/StrictModeNotifier.kt +++ b/app/src/debug/kotlin/org/koitharu/kotatsu/StrictModeNotifier.kt @@ -9,11 +9,12 @@ import android.os.Build import android.os.StrictMode import android.os.strictmode.Violation import androidx.annotation.RequiresApi +import androidx.core.app.PendingIntentCompat import androidx.core.content.getSystemService import androidx.fragment.app.strictmode.FragmentStrictMode import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asExecutor -import org.koitharu.kotatsu.core.ErrorReporterReceiver +import org.koitharu.kotatsu.core.util.ShareHelper import kotlin.math.absoluteValue import androidx.fragment.app.strictmode.Violation as FragmentViolation @@ -42,7 +43,7 @@ class StrictModeNotifier( override fun onViolation(violation: FragmentViolation) = showNotification(violation) private fun showNotification(violation: Throwable) = Notification.Builder(context, CHANNEL_ID) - .setSmallIcon(android.R.drawable.stat_notify_error) + .setSmallIcon(R.drawable.ic_bug) .setContentTitle(context.getString(R.string.strict_mode)) .setContentText(violation.message) .setStyle( @@ -51,7 +52,15 @@ class StrictModeNotifier( .setSummaryText(violation.message) .bigText(violation.stackTraceToString()), ).setShowWhen(true) - .setContentIntent(ErrorReporterReceiver.getPendingIntent(context, violation)) + .setContentIntent( + PendingIntentCompat.getActivity( + context, + 0, + ShareHelper(context).getShareTextIntent(violation.stackTraceToString()), + 0, + false, + ), + ) .setAutoCancel(true) .setGroup(CHANNEL_ID) .build() diff --git a/app/src/debug/res/drawable-anydpi-v24/ic_bug.xml b/app/src/debug/res/drawable-anydpi-v24/ic_bug.xml new file mode 100644 index 000000000..dc7fd8955 --- /dev/null +++ b/app/src/debug/res/drawable-anydpi-v24/ic_bug.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/debug/res/drawable-hdpi/ic_bug.png b/app/src/debug/res/drawable-hdpi/ic_bug.png new file mode 100644 index 0000000000000000000000000000000000000000..b4aa5f3c7668c6ccde4029bfff1698e52e64b757 GIT binary patch literal 417 zcmV;S0bc%zP)5bKg|3bQeVG^1yvlkp(=^9&}`N8|G!WIV+EQ8PE5*FA4;_ zhS?+7=U|`ZjeRqNuy;;3u+PCh%Ln_Sknolb!t4zH=J?9PWTabGmYEK;4sBU=!@LYP zXXRo36x@7+`=St?ms;!MVk#A2mJ}00000 LNkvXXu0mjfv5~q4 literal 0 HcmV?d00001 diff --git a/app/src/debug/res/drawable-mdpi/ic_bug.png b/app/src/debug/res/drawable-mdpi/ic_bug.png new file mode 100644 index 0000000000000000000000000000000000000000..726da962cd9619a328dee868d1107adb60a94e56 GIT binary patch literal 308 zcmV-40n7f0P)(Nj9bU!89{(rqGZ? z(a&RyX|X3DYqJ*w1}4x8N(!>XW@FB3gYw4Y%%FkQRQYS}1%ZK;8e^7xAB4$&A|Gis zH(wxQTJuf)E>xF_`bLHF%j<;4%8WCTlNpC+s z?>SI07~XTh&D@F+zbJo*&wE}>*ne>2+zXEPR{Ru+FVdXE=RF512E%&}xLGLGCF}5B zDJb+!^}DG0^-u-|y3mn^Qw~sv?;C@$7#f-H_aNr{Ph;L-@i~8nIl(pn0000sa42*cGuk3hHNr7 zDJrnbMkUx`-dIqP4x0_Z19Ot25=++m%8ZITyU5&RSnp>rlrD3Vpurbx62Lk0qoMFC zPD{uo`;^A=0zu>jexcANr})rM=m#hCM@K{MIn{@LLO-~rKRO!n#Hl{?6Z%1i{^;1G zEnt)W5L;d#h$suRrB6?T@V)&s2;bXgpI~g#9%5osu)rOs`p{442TA_OjyTnaenLMu zq(2y&f?uJ$Kmbt|a4)8w`zSWdcWSXuG!%a3PYUh&=_vz!?MW$QLkUW zL+ihxO5x$3PFve@KK+VgK0Mvhk(Iq-K7XP7YJuq$@j!K!ehxVw<>WuTpY!;!(tDtB z_UAo0{z}+AZf2e5eE)|+Vc+jGR;HNeE`l>3*F`odh+9Omr0w+Irf|mDPrUK>9d+v? ze|N_}P7(ac(p!8#N8o>{w@=v4e6a&Rg8e2m(DIxe~zW!l{OJPW{?n7A2&JOj{ar zSUvVO%hyAuA>kJO*&d&>=kJX<+`jJVS;oBL-gAvBRm&t5o;HZ>bbEf_iZz&huK*-2 z3Sk4)2ue?2KD&J3Wzno(SC2_*UjN{E-OO=s0q<24pv^Z*18i@#>`rUp)o1`C2W@66 zCfU^&o;OVlv`~C1W%u%y+KbD4>lRv_sf==dW3@tVBjZ)(;QX7Z4O5t3J>7dlXgAM< zB8Rw!Mk literal 0 HcmV?d00001 diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CaptchaNotifier.kt b/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CaptchaNotifier.kt index 83318f8ea..5ac7421e6 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CaptchaNotifier.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/browser/cloudflare/CaptchaNotifier.kt @@ -28,7 +28,7 @@ class CaptchaNotifier( return } val manager = NotificationManagerCompat.from(context) - val channel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_DEFAULT) + val channel = NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_LOW) .setName(context.getString(R.string.captcha_required)) .setShowBadge(true) .setVibrationEnabled(false) @@ -41,8 +41,8 @@ class CaptchaNotifier( .setData(exception.url.toUri()) val notification = NotificationCompat.Builder(context, CHANNEL_ID) .setContentTitle(channel.name) - .setPriority(NotificationCompat.PRIORITY_DEFAULT) - .setDefaults(NotificationCompat.DEFAULT_SOUND) + .setPriority(NotificationCompat.PRIORITY_LOW) + .setDefaults(0) .setSmallIcon(android.R.drawable.stat_notify_error) .setGroup(GROUP_CAPTCHA) .setAutoCancel(true) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt index 1edf3b662..8d2e34b9f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/DialogErrorObserver.kt @@ -8,6 +8,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.isSerializable import org.koitharu.kotatsu.parsers.exception.ParseException class DialogErrorObserver( @@ -32,7 +33,7 @@ class DialogErrorObserver( dialogBuilder.setPositiveButton(ExceptionResolver.getResolveStringId(value), listener) } else if (value is ParseException) { val fm = fragmentManager - if (fm != null) { + if (fm != null && value.isSerializable()) { dialogBuilder.setPositiveButton(R.string.details) { _, _ -> ErrorDetailsDialog.show(fm, value, value.url) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt index e39897cfc..d5b55b750 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/resolve/SnackbarErrorObserver.kt @@ -7,6 +7,7 @@ import com.google.android.material.snackbar.Snackbar import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.isSerializable import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner import org.koitharu.kotatsu.parsers.exception.ParseException @@ -33,7 +34,7 @@ class SnackbarErrorObserver( } } else if (value is ParseException) { val fm = fragmentManager - if (fm != null) { + if (fm != null && value.isSerializable()) { snackbar.setAction(R.string.details) { ErrorDetailsDialog.show(fm, value, value.url) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/io/NullOutputStream.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/io/NullOutputStream.kt new file mode 100644 index 000000000..d02cdf97b --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/io/NullOutputStream.kt @@ -0,0 +1,13 @@ +package org.koitharu.kotatsu.core.io + +import java.io.OutputStream +import java.util.Objects + +class NullOutputStream : OutputStream() { + + override fun write(b: Int) = Unit + + override fun write(b: ByteArray, off: Int, len: Int) { + Objects.checkFromIndexSize(off, len, b.size) + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ShareHelper.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ShareHelper.kt index fc486cb4f..3fa1b6e3f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ShareHelper.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ShareHelper.kt @@ -1,6 +1,7 @@ package org.koitharu.kotatsu.core.util import android.content.Context +import android.content.Intent import android.net.Uri import androidx.core.app.ShareCompat import androidx.core.content.FileProvider @@ -75,11 +76,9 @@ class ShareHelper(private val context: Context) { .startChooser() } - fun shareText(text: String) { - ShareCompat.IntentBuilder(context) - .setText(text) - .setType(TYPE_TEXT) - .setChooserTitle(R.string.share) - .startChooser() - } + fun getShareTextIntent(text: String): Intent = ShareCompat.IntentBuilder(context) + .setText(text) + .setType(TYPE_TEXT) + .setChooserTitle(R.string.share) + .createChooserIntent() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Bundle.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Bundle.kt index 34f3f440e..0a90ef83a 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Bundle.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Bundle.kt @@ -20,6 +20,10 @@ inline fun Bundle.getParcelableCompat(key: String): T? return BundleCompat.getParcelable(this, key, T::class.java) } +inline fun Bundle.requireParcelable(key: String): T = checkNotNull(getParcelableCompat(key)) { + "Parcelable of type \"${T::class.java.name}\" not found at \"$key\"" +} + inline fun Intent.getParcelableExtraCompat(key: String): T? { return IntentCompat.getParcelableExtra(this, key, T::class.java) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt index 41a51ce63..afb2117fe 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Throwable.kt @@ -24,6 +24,7 @@ import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException import org.koitharu.kotatsu.core.exceptions.WrongPasswordException import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver +import org.koitharu.kotatsu.core.io.NullOutputStream import org.koitharu.kotatsu.parsers.ErrorMessages.FILTER_BOTH_LOCALE_GENRES_NOT_SUPPORTED import org.koitharu.kotatsu.parsers.ErrorMessages.FILTER_BOTH_STATES_GENRES_NOT_SUPPORTED import org.koitharu.kotatsu.parsers.ErrorMessages.FILTER_MULTIPLE_GENRES_NOT_SUPPORTED @@ -35,6 +36,7 @@ import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.exception.ParseException import org.koitharu.kotatsu.parsers.exception.TooManyRequestExceptions import org.koitharu.kotatsu.scrobbling.common.domain.ScrobblerAuthRequiredException +import java.io.ObjectOutputStream import java.net.SocketTimeoutException import java.net.UnknownHostException @@ -181,3 +183,9 @@ fun Throwable.isWebViewUnavailable(): Boolean { @Suppress("FunctionName") fun NoSpaceLeftException() = IOException(MSG_NO_SPACE_LEFT) + +fun Throwable.isSerializable() = runCatching { + val oos = ObjectOutputStream(NullOutputStream()) + oos.writeObject(this) + oos.flush() +}.isSuccess diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsErrorObserver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsErrorObserver.kt index 482618a0a..745703330 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsErrorObserver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/DetailsErrorObserver.kt @@ -8,6 +8,7 @@ import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.ui.dialog.ErrorDetailsDialog import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.isNetworkError +import org.koitharu.kotatsu.core.util.ext.isSerializable import org.koitharu.kotatsu.parsers.exception.NotFoundException import org.koitharu.kotatsu.parsers.exception.ParseException @@ -38,7 +39,7 @@ class DetailsErrorObserver( value is ParseException -> { val fm = fragmentManager - if (fm != null) { + if (fm != null && value.isSerializable()) { snackbar.setAction(R.string.details) { ErrorDetailsDialog.show(fm, value, value.url) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt index 21a0d5639..e901d9079 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt @@ -17,6 +17,7 @@ import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.ui.widgets.ZoomControl import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.isLowRamDevice +import org.koitharu.kotatsu.core.util.ext.isSerializable import org.koitharu.kotatsu.databinding.ItemPageBinding import org.koitharu.kotatsu.parsers.util.ifZero import org.koitharu.kotatsu.reader.domain.PageLoader @@ -154,6 +155,7 @@ open class PageHolder( bindingInfo.buttonRetry.setText( ExceptionResolver.getResolveStringId(e).ifZero { R.string.try_again }, ) + bindingInfo.buttonErrorDetails.isVisible = e.isSerializable() bindingInfo.layoutError.isVisible = true bindingInfo.progressBar.hide() } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt index e2629e4a1..31501e97d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt @@ -11,6 +11,7 @@ import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.os.NetworkState import org.koitharu.kotatsu.core.util.GoneOnInvisibleListener import org.koitharu.kotatsu.core.util.ext.getDisplayMessage +import org.koitharu.kotatsu.core.util.ext.isSerializable import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding import org.koitharu.kotatsu.parsers.util.ifZero import org.koitharu.kotatsu.reader.domain.PageLoader @@ -128,6 +129,7 @@ class WebtoonHolder( bindingInfo.buttonRetry.setText( ExceptionResolver.getResolveStringId(e).ifZero { R.string.try_again }, ) + bindingInfo.buttonErrorDetails.isVisible = e.isSerializable() bindingInfo.layoutError.isVisible = true bindingInfo.progressBar.hide() } diff --git a/app/src/main/res/menu/opt_local.xml b/app/src/main/res/menu/opt_local.xml index e00b4b7d3..0403421a9 100644 --- a/app/src/main/res/menu/opt_local.xml +++ b/app/src/main/res/menu/opt_local.xml @@ -9,9 +9,15 @@ android:title="@string/_import" app:showAsAction="never" /> + +