Fix crashes
This commit is contained in:
@@ -14,8 +14,8 @@ android {
|
|||||||
applicationId 'org.koitharu.kotatsu'
|
applicationId 'org.koitharu.kotatsu'
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 32
|
targetSdkVersion 32
|
||||||
versionCode 423
|
versionCode 424
|
||||||
versionName '3.4.11'
|
versionName '3.4.12'
|
||||||
generatedDensities = []
|
generatedDensities = []
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
@@ -119,8 +119,8 @@ dependencies {
|
|||||||
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
|
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
|
||||||
implementation 'com.github.solkin:disk-lru-cache:1.4'
|
implementation 'com.github.solkin:disk-lru-cache:1.4'
|
||||||
|
|
||||||
implementation 'ch.acra:acra-mail:5.9.5'
|
implementation 'ch.acra:acra-mail:5.9.6'
|
||||||
implementation 'ch.acra:acra-dialog:5.9.5'
|
implementation 'ch.acra:acra-dialog:5.9.6'
|
||||||
|
|
||||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
|
||||||
|
|
||||||
|
|||||||
4
app/proguard-rules.pro
vendored
4
app/proguard-rules.pro
vendored
@@ -10,4 +10,6 @@
|
|||||||
}
|
}
|
||||||
-keep public class ** extends org.koitharu.kotatsu.base.ui.BaseFragment
|
-keep public class ** extends org.koitharu.kotatsu.base.ui.BaseFragment
|
||||||
-keep class org.koitharu.kotatsu.core.db.entity.* { *; }
|
-keep class org.koitharu.kotatsu.core.db.entity.* { *; }
|
||||||
-dontwarn okhttp3.internal.platform.ConscryptPlatform
|
-dontwarn okhttp3.internal.platform.ConscryptPlatform
|
||||||
|
-keep class org.koitharu.kotatsu.core.exceptions.* { *; }
|
||||||
|
-keep class org.koitharu.kotatsu.settings.NotificationSettingsLegacyFragment
|
||||||
@@ -25,7 +25,7 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
|
|||||||
|
|
||||||
override fun onInflateView(
|
override fun onInflateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?
|
container: ViewGroup?,
|
||||||
) = FragmentCloudflareBinding.inflate(inflater, container, false)
|
) = FragmentCloudflareBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
@@ -49,6 +49,7 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
|
|||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
binding.webView.stopLoading()
|
binding.webView.stopLoading()
|
||||||
|
binding.webView.destroy()
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@ class CloudFlareDialog : AlertDialogFragment<FragmentCloudflareBinding>(), Cloud
|
|||||||
|
|
||||||
override fun onCheckPassed() {
|
override fun onCheckPassed() {
|
||||||
pendingResult.putBoolean(EXTRA_RESULT, true)
|
pendingResult.putBoolean(EXTRA_RESULT, true)
|
||||||
dismiss()
|
dismissAllowingStateLoss()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package org.koitharu.kotatsu.settings
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -47,7 +49,7 @@ class SourceSettingsFragment : BasePreferenceFragment(0) {
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
findPreference<Preference>(KEY_AUTH)?.run {
|
findPreference<Preference>(KEY_AUTH)?.run {
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
loadUsername(this)
|
loadUsername(viewLifecycleOwner, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,7 +64,7 @@ class SourceSettingsFragment : BasePreferenceFragment(0) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadUsername(preference: Preference) = viewLifecycleScope.launch {
|
private fun loadUsername(owner: LifecycleOwner, preference: Preference) = owner.lifecycleScope.launch {
|
||||||
runCatching {
|
runCatching {
|
||||||
preference.summary = null
|
preference.summary = null
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
@@ -89,11 +91,12 @@ class SourceSettingsFragment : BasePreferenceFragment(0) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveError(error: Throwable): Unit {
|
private fun resolveError(error: Throwable) {
|
||||||
viewLifecycleScope.launch {
|
viewLifecycleScope.launch {
|
||||||
if (exceptionResolver.resolve(error)) {
|
if (exceptionResolver.resolve(error)) {
|
||||||
val pref = findPreference<Preference>(KEY_AUTH) ?: return@launch
|
val pref = findPreference<Preference>(KEY_AUTH) ?: return@launch
|
||||||
loadUsername(pref)
|
val lifecycleOwner = awaitViewLifecycle()
|
||||||
|
loadUsername(lifecycleOwner, pref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import coil.request.ImageResult
|
|||||||
import coil.request.SuccessResult
|
import coil.request.SuccessResult
|
||||||
import coil.util.CoilUtils
|
import coil.util.CoilUtils
|
||||||
import com.google.android.material.progressindicator.BaseProgressIndicator
|
import com.google.android.material.progressindicator.BaseProgressIndicator
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import org.koitharu.kotatsu.core.network.CommonHeaders
|
import org.koitharu.kotatsu.core.network.CommonHeaders
|
||||||
import org.koitharu.kotatsu.utils.progress.ImageRequestIndicatorListener
|
import org.koitharu.kotatsu.utils.progress.ImageRequestIndicatorListener
|
||||||
|
|
||||||
@@ -45,9 +46,28 @@ fun ImageResult.toBitmapOrNull() = when (this) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun ImageRequest.Builder.referer(referer: String): ImageRequest.Builder {
|
fun ImageRequest.Builder.referer(referer: String): ImageRequest.Builder {
|
||||||
return setHeader(CommonHeaders.REFERER, referer)
|
if (referer.isEmpty()) {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
setHeader(CommonHeaders.REFERER, referer)
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
val baseUrl = referer.baseUrl()
|
||||||
|
if (baseUrl != null) {
|
||||||
|
setHeader(CommonHeaders.REFERER, baseUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ImageRequest.Builder.indicator(indicator: BaseProgressIndicator<*>): ImageRequest.Builder {
|
fun ImageRequest.Builder.indicator(indicator: BaseProgressIndicator<*>): ImageRequest.Builder {
|
||||||
return listener(ImageRequestIndicatorListener(indicator))
|
return listener(ImageRequestIndicatorListener(indicator))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.baseUrl(): String? {
|
||||||
|
return (this.toHttpUrlOrNull()?.newBuilder("/") ?: return null)
|
||||||
|
.username("")
|
||||||
|
.password("")
|
||||||
|
.build()
|
||||||
|
.toString()
|
||||||
}
|
}
|
||||||
@@ -7,8 +7,12 @@ import androidx.fragment.app.DialogFragment
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.coroutineScope
|
import androidx.lifecycle.coroutineScope
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
|
|
||||||
inline fun <T : Fragment> T.withArgs(size: Int, block: Bundle.() -> Unit): T {
|
inline fun <T : Fragment> T.withArgs(size: Int, block: Bundle.() -> Unit): T {
|
||||||
val b = Bundle(size)
|
val b = Bundle(size)
|
||||||
@@ -49,4 +53,20 @@ fun DialogFragment.showAllowStateLoss(manager: FragmentManager, tag: String?) {
|
|||||||
|
|
||||||
fun Fragment.addMenuProvider(provider: MenuProvider) {
|
fun Fragment.addMenuProvider(provider: MenuProvider) {
|
||||||
requireActivity().addMenuProvider(provider, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
requireActivity().addMenuProvider(provider, viewLifecycleOwner, Lifecycle.State.RESUMED)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun Fragment.awaitViewLifecycle(): LifecycleOwner = suspendCancellableCoroutine { cont ->
|
||||||
|
val liveData = viewLifecycleOwnerLiveData
|
||||||
|
val observer = object : Observer<LifecycleOwner> {
|
||||||
|
override fun onChanged(result: LifecycleOwner?) {
|
||||||
|
if (result != null) {
|
||||||
|
liveData.removeObserver(this)
|
||||||
|
cont.resume(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
liveData.observeForever(observer)
|
||||||
|
cont.invokeOnCancellation {
|
||||||
|
liveData.removeObserver(observer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user