Option to enable exit confirmation

This commit is contained in:
Koitharu
2022-07-13 10:30:30 +03:00
parent d6ff996dbe
commit 334e08730e
5 changed files with 70 additions and 22 deletions

View File

@@ -130,6 +130,9 @@ class AppSettings(context: Context) {
get() = prefs.getBoolean(KEY_PROTECT_APP_BIOMETRIC, true) get() = prefs.getBoolean(KEY_PROTECT_APP_BIOMETRIC, true)
set(value) = prefs.edit { putBoolean(KEY_PROTECT_APP_BIOMETRIC, value) } set(value) = prefs.edit { putBoolean(KEY_PROTECT_APP_BIOMETRIC, value) }
val isExitConfirmationEnabled: Boolean
get() = prefs.getBoolean(KEY_EXIT_CONFIRM, false)
var sourcesOrder: List<String> var sourcesOrder: List<String>
get() = prefs.getString(KEY_SOURCES_ORDER, null) get() = prefs.getString(KEY_SOURCES_ORDER, null)
?.split('|') ?.split('|')
@@ -306,6 +309,7 @@ class AppSettings(context: Context) {
const val KEY_DOWNLOADS_SLOWDOWN = "downloads_slowdown" const val KEY_DOWNLOADS_SLOWDOWN = "downloads_slowdown"
const val KEY_ALL_FAVOURITES_VISIBLE = "all_favourites_visible" const val KEY_ALL_FAVOURITES_VISIBLE = "all_favourites_visible"
const val KEY_DOH = "doh" const val KEY_DOH = "doh"
const val KEY_EXIT_CONFIRM = "exit_confirm"
// About // About
const val KEY_APP_UPDATE = "app_update" const val KEY_APP_UPDATE = "app_update"

View File

@@ -0,0 +1,54 @@
package org.koitharu.kotatsu.main.ui
import android.view.View
import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.koin.android.ext.android.get
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.observeAsFlow
class ExitCallback(
private val activity: ComponentActivity,
private val snackbarHost: View,
) : OnBackPressedCallback(false) {
private var job: Job? = null
init {
observeSettings()
}
override fun handleOnBackPressed() {
job?.cancel()
job = activity.lifecycleScope.launch {
resetExitConfirmation()
}
}
private suspend fun resetExitConfirmation() {
isEnabled = false
val snackbar = Snackbar.make(snackbarHost, R.string.confirm_exit, Snackbar.LENGTH_INDEFINITE)
snackbar.show()
delay(2000)
snackbar.dismiss()
isEnabled = true
}
private fun observeSettings() {
activity.get<AppSettings>()
.observeAsFlow(AppSettings.KEY_EXIT_CONFIRM) { isExitConfirmationEnabled }
.flowOn(Dispatchers.Default)
.onEach { isEnabled = it }
.launchIn(activity.lifecycleScope)
}
}

View File

@@ -4,7 +4,6 @@ import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup.MarginLayoutParams import android.view.ViewGroup.MarginLayoutParams
import android.widget.Toast
import androidx.activity.result.ActivityResultCallback import androidx.activity.result.ActivityResultCallback
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
@@ -21,8 +20,6 @@ import com.google.android.material.appbar.AppBarLayout.LayoutParams.*
import com.google.android.material.navigation.NavigationBarView import com.google.android.material.navigation.NavigationBarView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
@@ -63,8 +60,6 @@ class MainActivity :
View.OnFocusChangeListener, View.OnFocusChangeListener,
SearchSuggestionListener, NavigationBarView.OnItemSelectedListener { SearchSuggestionListener, NavigationBarView.OnItemSelectedListener {
private var isConfirmingExit: Boolean = false
private val viewModel by viewModel<MainViewModel>() private val viewModel by viewModel<MainViewModel>()
private val searchSuggestionViewModel by viewModel<SearchSuggestionViewModel>() private val searchSuggestionViewModel by viewModel<SearchSuggestionViewModel>()
private val voiceInputLauncher = registerForActivityResult(VoiceInputContract(), VoiceInputCallback()) private val voiceInputLauncher = registerForActivityResult(VoiceInputContract(), VoiceInputCallback())
@@ -99,6 +94,7 @@ class MainActivity :
binding.navRail?.headerView?.setOnClickListener(this) binding.navRail?.headerView?.setOnClickListener(this)
binding.searchView.isVoiceSearchEnabled = voiceInputLauncher.resolve(this, null) != null binding.searchView.isVoiceSearchEnabled = voiceInputLauncher.resolve(this, null) != null
onBackPressedDispatcher.addCallback(ExitCallback(this, binding.container))
supportFragmentManager.findFragmentByTag(TAG_PRIMARY)?.let { supportFragmentManager.findFragmentByTag(TAG_PRIMARY)?.let {
if (it is LibraryFragment) binding.fab?.show() else binding.fab?.hide() if (it is LibraryFragment) binding.fab?.show() else binding.fab?.hide()
} ?: onNavigationItemSelected(navBar.selectedItemId) } ?: onNavigationItemSelected(navBar.selectedItemId)
@@ -136,7 +132,6 @@ class MainActivity :
setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
runOnCommit { onSearchClosed() } runOnCommit { onSearchClosed() }
} }
shouldHandleExitConfirmation() -> lifecycleScope.launch { resetExitConfirmation() }
else -> super.onBackPressed() else -> super.onBackPressed()
} }
} }
@@ -153,19 +148,6 @@ class MainActivity :
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private suspend fun resetExitConfirmation() {
isConfirmingExit = true
val toast = Toast.makeText(this, R.string.confirm_exit, Toast.LENGTH_LONG)
toast.show()
delay(2000)
toast.cancel()
isConfirmingExit = false
}
private fun shouldHandleExitConfirmation(): Boolean {
return !isConfirmingExit
}
override fun onClick(v: View) { override fun onClick(v: View) {
when (v.id) { when (v.id) {
R.id.fab -> viewModel.openLastReader() R.id.fab -> viewModel.openLastReader()

View File

@@ -337,5 +337,7 @@
<string name="changelog">Changelog</string> <string name="changelog">Changelog</string>
<string name="explore">Explore</string> <string name="explore">Explore</string>
<string name="tools">Tools</string> <string name="tools">Tools</string>
<string name="confirm_exit">Press back again to exit</string> <string name="confirm_exit">Press "Back" again to exit</string>
<string name="exit_confirmation_summary">Press "Back" twice to exit the app</string>
<string name="exit_confirmation">Exit confirmation</string>
</resources> </resources>

View File

@@ -43,11 +43,17 @@
android:valueTo="150" android:valueTo="150"
app:defaultValue="100" /> app:defaultValue="100" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="exit_confirm"
android:summary="@string/exit_confirmation_summary"
android:title="@string/exit_confirmation"
app:allowDividerAbove="true" />
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:key="protect_app" android:key="protect_app"
android:persistent="false" android:persistent="false"
android:summary="@string/protect_application_summary" android:summary="@string/protect_application_summary"
android:title="@string/protect_application" android:title="@string/protect_application" />
app:allowDividerAbove="true" />
</PreferenceScreen> </PreferenceScreen>