Option to enable exit confirmation

pull/163/head
Koitharu 4 years ago
parent d6ff996dbe
commit 334e08730e
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -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"

@ -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)
}
}

@ -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()

@ -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>

@ -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>
Loading…
Cancel
Save