diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e441e910f..48e80815b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -46,7 +46,7 @@
android:allowBackup="true"
android:backupAgent="org.koitharu.kotatsu.settings.backup.AppBackupAgent"
android:dataExtractionRules="@xml/backup_rules"
- android:enableOnBackInvokedCallback="true"
+ android:enableOnBackInvokedCallback="@bool/is_predictive_back_enabled"
android:fullBackupContent="@xml/backup_content"
android:fullBackupOnly="true"
android:icon="@mipmap/ic_launcher"
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/CaughtException.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/CaughtException.kt
index 3548c0872..d606b4c6e 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/CaughtException.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/CaughtException.kt
@@ -1,3 +1,5 @@
package org.koitharu.kotatsu.core.exceptions
-class CaughtException(cause: Throwable) : RuntimeException("${cause.javaClass.simpleName}(${cause.message})", cause)
+class CaughtException(
+ override val cause: Throwable
+) : RuntimeException("${cause.javaClass.simpleName}(${cause.message})", cause)
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/WrapperIOException.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/WrapperIOException.kt
new file mode 100644
index 000000000..d9c9c7aa9
--- /dev/null
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/exceptions/WrapperIOException.kt
@@ -0,0 +1,5 @@
+package org.koitharu.kotatsu.core.exceptions
+
+import okio.IOException
+
+class WrapperIOException(override val cause: Exception) : IOException(cause)
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/AppProxySelector.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/AppProxySelector.kt
index 1424f1f31..4ac33ad07 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/AppProxySelector.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/AppProxySelector.kt
@@ -35,7 +35,7 @@ class AppProxySelector(
if (type == Proxy.Type.DIRECT) {
return Proxy.NO_PROXY
}
- if (address.isNullOrEmpty() || port == 0) {
+ if (address.isNullOrEmpty() || port < 0 || port > 0xFFFF) {
throw ProxyConfigException()
}
cachedProxy?.let {
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/GZipInterceptor.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/GZipInterceptor.kt
index 09a544105..f4f666dfb 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/core/network/GZipInterceptor.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/network/GZipInterceptor.kt
@@ -1,19 +1,26 @@
package org.koitharu.kotatsu.core.network
import okhttp3.Interceptor
+import okhttp3.MultipartBody
import okhttp3.Response
import okio.IOException
+import org.koitharu.kotatsu.core.exceptions.WrapperIOException
import org.koitharu.kotatsu.core.network.CommonHeaders.CONTENT_ENCODING
class GZipInterceptor : Interceptor {
- override fun intercept(chain: Interceptor.Chain): Response {
- val newRequest = chain.request().newBuilder()
- newRequest.addHeader(CONTENT_ENCODING, "gzip")
- return try {
+ override fun intercept(chain: Interceptor.Chain): Response = try {
+ val request = chain.request()
+ if (request.body is MultipartBody) {
+ chain.proceed(request)
+ } else {
+ val newRequest = request.newBuilder()
+ newRequest.addHeader(CONTENT_ENCODING, "gzip")
chain.proceed(newRequest.build())
- } catch (e: NullPointerException) {
- throw IOException(e)
}
+ } catch (e: IOException) {
+ throw e
+ } catch (e: Exception) {
+ throw WrapperIOException(e)
}
}
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 5811cfa65..c201853cf 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.ProxyConfigException
import org.koitharu.kotatsu.core.exceptions.SyncApiException
import org.koitharu.kotatsu.core.exceptions.UnsupportedFileException
import org.koitharu.kotatsu.core.exceptions.UnsupportedSourceException
+import org.koitharu.kotatsu.core.exceptions.WrapperIOException
import org.koitharu.kotatsu.core.exceptions.WrongPasswordException
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.io.NullOutputStream
@@ -54,6 +55,8 @@ fun Throwable.getDisplayMessage(resources: Resources): String = getDisplayMessag
?: resources.getString(R.string.error_occurred)
private fun Throwable.getDisplayMessageOrNull(resources: Resources): String? = when (this) {
+ is CaughtException -> cause.getDisplayMessageOrNull(resources)
+ is WrapperIOException -> cause.getDisplayMessageOrNull(resources)
is ScrobblerAuthRequiredException -> resources.getString(
R.string.scrobbler_auth_required,
resources.getString(scrobbler.titleResId),
@@ -141,7 +144,8 @@ fun Throwable.getCauseUrl(): String? = when (this) {
is ParseException -> url
is NotFoundException -> url
is TooManyRequestExceptions -> url
- is CaughtException -> cause?.getCauseUrl()
+ is CaughtException -> cause.getCauseUrl()
+ is WrapperIOException -> cause.getCauseUrl()
is NoDataReceivedException -> url
is CloudFlareBlockedException -> url
is CloudFlareProtectedException -> url
@@ -175,7 +179,10 @@ fun Throwable.isReportable(): Boolean {
return true
}
if (this is CaughtException) {
- return cause?.isReportable() == true
+ return cause.isReportable()
+ }
+ if (this is WrapperIOException) {
+ return cause.isReportable()
}
if (ExceptionResolver.canResolve(this)) {
return false
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/PagesCache.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/PagesCache.kt
index 3b8a9dd11..b4a414dfa 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/PagesCache.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/PagesCache.kt
@@ -22,6 +22,7 @@ import org.koitharu.kotatsu.core.util.ext.subdir
import org.koitharu.kotatsu.core.util.ext.takeIfReadable
import org.koitharu.kotatsu.core.util.ext.takeIfWriteable
import org.koitharu.kotatsu.core.util.ext.writeAllCancellable
+import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import org.koitharu.kotatsu.parsers.util.suspendlazy.suspendLazy
import java.io.File
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt
index 04b5759b4..0e05ea9a1 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt
@@ -185,7 +185,7 @@ class PageLoader @Inject constructor(
prefetchLock.withLock {
while (prefetchQueue.isNotEmpty()) {
val page = prefetchQueue.pollFirst() ?: return@launch
- if (cache.get(page.url) == null) {
+ if (cache.get(page.url) == null) { // FIXME use pageUrl
synchronized(tasks) {
tasks[page.id] = loadPageAsyncImpl(page, skipCache = false, isPrefetch = true)
}
@@ -203,6 +203,7 @@ class PageLoader @Inject constructor(
val progress = MutableStateFlow(PROGRESS_UNDEFINED)
val deferred = loaderScope.async {
if (!skipCache) {
+ // FIXME use pageUrl
cache.get(page.url)?.let { return@async it.toUri() }
}
counter.incrementAndGet()
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt
index 7a5ca06d2..34bca6de8 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt
@@ -209,6 +209,9 @@ class ReaderInfoBarView @JvmOverloads constructor(
}
private fun Drawable.drawWithOutline(canvas: Canvas) {
+ if (bounds.isEmpty) {
+ return
+ }
var requiredScale = (bounds.width() + paint.strokeWidth * 2f) / bounds.width().toFloat()
setTint(colorOutline)
canvas.withScale(requiredScale, requiredScale, bounds.exactCenterX(), bounds.exactCenterY()) {
diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/widget/WidgetUpdater.kt b/app/src/main/kotlin/org/koitharu/kotatsu/widget/WidgetUpdater.kt
index c5fd21e71..1508ec24a 100644
--- a/app/src/main/kotlin/org/koitharu/kotatsu/widget/WidgetUpdater.kt
+++ b/app/src/main/kotlin/org/koitharu/kotatsu/widget/WidgetUpdater.kt
@@ -30,7 +30,7 @@ class WidgetUpdater @Inject constructor(
private fun updateWidgets(cls: Class<*>) {
val intent = Intent(context, cls)
intent.action = AppWidgetManager.ACTION_APPWIDGET_UPDATE
- val ids = AppWidgetManager.getInstance(context)
+ val ids = (AppWidgetManager.getInstance(context) ?: return)
.getAppWidgetIds(ComponentName(context, cls))
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids)
context.sendBroadcast(intent)
diff --git a/app/src/main/res/values/bools.xml b/app/src/main/res/values/bools.xml
index 8a68dc46b..dee4d7e61 100644
--- a/app/src/main/res/values/bools.xml
+++ b/app/src/main/res/values/bools.xml
@@ -6,4 +6,5 @@
true
false
true
+ true
diff --git a/app/src/release/res/values/bools.xml b/app/src/release/res/values/bools.xml
new file mode 100644
index 000000000..a491a51a2
--- /dev/null
+++ b/app/src/release/res/values/bools.xml
@@ -0,0 +1,5 @@
+
+
+
+ false
+