Fix crashes and improve predictive back support

This commit is contained in:
Koitharu
2024-05-25 10:14:39 +03:00
parent a7e2cfc878
commit 2ae488544b
10 changed files with 56 additions and 22 deletions

View File

@@ -94,6 +94,7 @@ dependencies {
implementation 'androidx.core:core-ktx:1.13.1' implementation 'androidx.core:core-ktx:1.13.1'
implementation 'androidx.activity:activity-ktx:1.9.0' implementation 'androidx.activity:activity-ktx:1.9.0'
implementation 'androidx.fragment:fragment-ktx:1.7.1' implementation 'androidx.fragment:fragment-ktx:1.7.1'
implementation 'androidx.transition:transition-ktx:1.5.0'
implementation 'androidx.collection:collection-ktx:1.4.0' implementation 'androidx.collection:collection-ktx:1.4.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0'
implementation 'androidx.lifecycle:lifecycle-service:2.8.0' implementation 'androidx.lifecycle:lifecycle-service:2.8.0'

View File

@@ -108,8 +108,10 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
viewBinding.webView.stopLoading() if (hasViewBinding()) {
viewBinding.webView.destroy() viewBinding.webView.stopLoading()
viewBinding.webView.destroy()
}
} }
override fun onLoadingStateChanged(isLoading: Boolean) { override fun onLoadingStateChanged(isLoading: Boolean) {

View File

@@ -16,6 +16,7 @@ import okhttp3.OkHttpClient
import okhttp3.Response import okhttp3.Response
import okhttp3.ResponseBody.Companion.asResponseBody import okhttp3.ResponseBody.Companion.asResponseBody
import okio.Buffer import okio.Buffer
import okio.IOException
import org.koitharu.kotatsu.core.network.MangaHttpClient import org.koitharu.kotatsu.core.network.MangaHttpClient
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.core.prefs.SourceSettings import org.koitharu.kotatsu.core.prefs.SourceSettings
@@ -29,6 +30,7 @@ import org.koitharu.kotatsu.parsers.bitmap.Bitmap
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.network.UserAgents import org.koitharu.kotatsu.parsers.network.UserAgents
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.Locale import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@@ -75,7 +77,10 @@ class MangaLoaderContextImpl @Inject constructor(
return LocaleListCompat.getAdjustedDefault().toList() return LocaleListCompat.getAdjustedDefault().toList()
} }
override fun redrawImageResponse(response: Response, redraw: (image: Bitmap) -> Bitmap): Response { override fun redrawImageResponse(
response: Response,
redraw: (image: Bitmap) -> Bitmap
): Response = runCatchingCancellable {
val image = response.requireBody().byteStream() val image = response.requireBody().byteStream()
val opts = BitmapFactory.Options() val opts = BitmapFactory.Options()
@@ -87,9 +92,15 @@ class MangaLoaderContextImpl @Inject constructor(
result.compressTo(it.outputStream()) result.compressTo(it.outputStream())
}.asResponseBody("image/jpeg".toMediaType()) }.asResponseBody("image/jpeg".toMediaType())
return response.newBuilder() response.newBuilder()
.body(body) .body(body)
.build() .build()
}.getOrElse { error ->
if (error is IOException) {
throw error
} else {
throw IOException(error.message, error)
}
} }
override fun createBitmap(width: Int, height: Int): Bitmap { override fun createBitmap(width: Int, height: Int): Bitmap {

View File

@@ -92,9 +92,6 @@ abstract class BaseActivity<B : ViewBinding> :
} }
override fun onSupportNavigateUp(): Boolean { override fun onSupportNavigateUp(): Boolean {
if (supportFragmentManager.popBackStackImmediate()) {
return false
}
dispatchNavigateUp() dispatchNavigateUp()
return true return true
} }
@@ -159,6 +156,8 @@ abstract class BaseActivity<B : ViewBinding> :
} }
} }
protected fun hasViewBinding() = ::viewBinding.isInitialized
@EntryPoint @EntryPoint
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
interface BaseActivityEntryPoint { interface BaseActivityEntryPoint {

View File

@@ -1,22 +1,34 @@
package org.koitharu.kotatsu.core.ui.sheet package org.koitharu.kotatsu.core.ui.sheet
import android.annotation.SuppressLint
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.activity.BackEventCompat
import androidx.activity.OnBackPressedCallback import androidx.activity.OnBackPressedCallback
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_COLLAPSED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HALF_EXPANDED import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HALF_EXPANDED
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
class BottomSheetCollapseCallback( class BottomSheetCollapseCallback(
private val behavior: BottomSheetBehavior<*>, private val sheet: ViewGroup,
) : OnBackPressedCallback(behavior.state == STATE_EXPANDED) { private val behavior: BottomSheetBehavior<*> = BottomSheetBehavior.from(sheet),
) : OnBackPressedCallback(behavior.state == STATE_EXPANDED || behavior.state == STATE_HALF_EXPANDED) {
init { init {
behavior.addBottomSheetCallback( behavior.addBottomSheetCallback(
object : BottomSheetBehavior.BottomSheetCallback() { object : BottomSheetBehavior.BottomSheetCallback() {
@SuppressLint("SwitchIntDef")
override fun onStateChanged(view: View, state: Int) { override fun onStateChanged(view: View, state: Int) {
isEnabled = state == STATE_EXPANDED || state == STATE_HALF_EXPANDED when (state) {
STATE_EXPANDED,
STATE_HALF_EXPANDED -> isEnabled = true
STATE_COLLAPSED,
STATE_HIDDEN -> isEnabled = false
}
} }
override fun onSlide(p0: View, p1: Float) = Unit override fun onSlide(p0: View, p1: Float) = Unit
@@ -24,7 +36,11 @@ class BottomSheetCollapseCallback(
) )
} }
override fun handleOnBackPressed() { override fun handleOnBackPressed() = behavior.handleBackInvoked()
behavior.state = STATE_COLLAPSED
} override fun handleOnBackCancelled() = behavior.cancelBackProgress()
override fun handleOnBackProgressed(backEvent: BackEventCompat) = behavior.updateBackProgress(backEvent)
override fun handleOnBackStarted(backEvent: BackEventCompat) = behavior.startBackProgress(backEvent)
} }

View File

@@ -31,7 +31,6 @@ import coil.request.ImageRequest
import coil.request.SuccessResult import coil.request.SuccessResult
import coil.transform.CircleCropTransformation import coil.transform.CircleCropTransformation
import coil.util.CoilUtils import coil.util.CoilUtils
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@@ -153,8 +152,8 @@ class DetailsActivity :
viewBinding.textViewDescription.movementMethod = LinkMovementMethodCompat.getInstance() viewBinding.textViewDescription.movementMethod = LinkMovementMethodCompat.getInstance()
viewBinding.chipsTags.onChipClickListener = this viewBinding.chipsTags.onChipClickListener = this
TitleScrollCoordinator(viewBinding.textViewTitle).attach(viewBinding.scrollView) TitleScrollCoordinator(viewBinding.textViewTitle).attach(viewBinding.scrollView)
viewBinding.containerBottomSheet?.let { BottomSheetBehavior.from(it) }?.let { behavior -> viewBinding.containerBottomSheet?.let { sheet ->
onBackPressedDispatcher.addCallback(BottomSheetCollapseCallback(behavior)) onBackPressedDispatcher.addCallback(BottomSheetCollapseCallback(sheet))
} }
viewModel.details.filterNotNull().observe(this, ::onMangaUpdated) viewModel.details.filterNotNull().observe(this, ::onMangaUpdated)

View File

@@ -125,7 +125,7 @@ class SettingsActivity :
supportFragmentManager.commit { supportFragmentManager.commit {
setReorderingAllowed(true) setReorderingAllowed(true)
replace(R.id.container, fragment) replace(R.id.container, fragment)
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN) setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
if (!isMasterDetails || (hasFragment && !isFromRoot)) { if (!isMasterDetails || (hasFragment && !isFromRoot)) {
addToBackStack(null) addToBackStack(null)
} }

View File

@@ -11,7 +11,6 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
@@ -41,7 +40,13 @@ class MangaDirectorySelectDialog : AlertDialogFragment<DialogDirectorySelectBind
) { ) {
if (it) { if (it) {
viewModel.refresh() viewModel.refresh()
pickFileTreeLauncher.launch(null) if (!pickFileTreeLauncher.tryLaunch(null)) {
Toast.makeText(
context ?: return@registerForActivityResult,
R.string.operation_not_supported,
Toast.LENGTH_SHORT,
).show()
}
} }
} }

View File

@@ -68,7 +68,7 @@
tools:text="@string/appearance" /> tools:text="@string/appearance" />
<androidx.fragment.app.FragmentContainerView <androidx.fragment.app.FragmentContainerView
android:id="@+id/container" android:id="@id/container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />

View File

@@ -9,12 +9,13 @@
android:id="@+id/appbar" android:id="@+id/appbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:fitsSystemWindows="true"> android:fitsSystemWindows="true"
app:liftOnScroll="false">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@id/toolbar" android:id="@id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="wrap_content"
app:layout_collapseMode="pin" /> app:layout_collapseMode="pin" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>