Fix back press exit confirmation

This commit is contained in:
Koitharu
2025-07-05 07:45:37 +03:00
parent e549d141a4
commit 40584cb6f5
3 changed files with 36 additions and 14 deletions

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.util.ext
import android.content.ActivityNotFoundException
import android.content.res.Resources
import android.database.sqlite.SQLiteFullException
import androidx.annotation.DrawableRes
import coil3.network.HttpException
import com.davemorrissey.labs.subscaleview.decoder.ImageDecodeException
@@ -91,6 +92,7 @@ private fun Throwable.getDisplayMessageOrNull(resources: Resources): String? = w
}
}
is SQLiteFullException -> resources.getString(R.string.error_no_space_left)
is UnsupportedFileException -> resources.getString(R.string.text_file_not_supported)
is BadBackupFormatException -> resources.getString(R.string.unsupported_backup_message)
is FileNotFoundException -> parseMessage(resources) ?: message

View File

@@ -3,13 +3,15 @@ package org.koitharu.kotatsu.main.ui
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.lifecycle.lifecycleScope
import com.google.android.material.search.SearchView
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
@@ -19,12 +21,24 @@ import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
class ExitCallback(
private val activity: MainActivity,
private val snackbarHost: View,
) : OnBackPressedCallback(false) {
) : OnBackPressedCallback(false), SearchView.TransitionListener {
private var job: Job? = null
private val isSearchOpen = MutableStateFlow(activity.viewBinding.searchView.isShowing)
private val isDisabledByTimeout = MutableStateFlow(false)
init {
observeSettings()
activity.lifecycleScope.launch {
combine(
observeSettings(),
isSearchOpen,
isDisabledByTimeout,
) { enabledInSettings, searchOpen, disabledTemporary ->
enabledInSettings && !searchOpen && !disabledTemporary
}.collect {
isEnabled = it
}
}
}
override fun handleOnBackPressed() {
@@ -34,21 +48,25 @@ class ExitCallback(
}
}
override fun onStateChanged(
searchView: SearchView,
previousState: SearchView.TransitionState,
newState: SearchView.TransitionState
) {
isSearchOpen.value = newState >= SearchView.TransitionState.SHOWING
}
private suspend fun resetExitConfirmation() {
isEnabled = false
isDisabledByTimeout.value = true
val snackbar = Snackbar.make(snackbarHost, R.string.confirm_exit, Snackbar.LENGTH_INDEFINITE)
snackbar.anchorView = (activity as? BottomNavOwner)?.bottomNav
snackbar.show()
delay(2000)
snackbar.dismiss()
isEnabled = true
isDisabledByTimeout.value = false
}
private fun observeSettings() {
activity.settings
.observeAsFlow(AppSettings.KEY_EXIT_CONFIRM) { isExitConfirmationEnabled }
.flowOn(Dispatchers.Default)
.onEach { isEnabled = it }
.launchIn(activity.lifecycleScope)
}
private fun observeSettings(): Flow<Boolean> = activity.settings
.observeAsFlow(AppSettings.KEY_EXIT_CONFIRM) { isExitConfirmationEnabled }
.flowOn(Dispatchers.Default)
}

View File

@@ -127,7 +127,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
addMenuProvider(MainMenuProvider(router, viewModel))
onBackPressedDispatcher.addCallback(ExitCallback(this, viewBinding.container))
val exitCallback = ExitCallback(this, viewBinding.container)
onBackPressedDispatcher.addCallback(exitCallback)
onBackPressedDispatcher.addCallback(navigationDelegate)
if (savedInstanceState == null) {
@@ -145,6 +146,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
searchSuggestionViewModel.isIncognitoModeEnabled.observe(this, this::onIncognitoModeChanged)
viewBinding.bottomNav?.addOnLayoutChangeListener(this)
viewBinding.searchView.addTransitionListener(this)
viewBinding.searchView.addTransitionListener(exitCallback)
initSearch()
}