Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.EditText
import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback
import androidx.annotation.CheckResult
import androidx.appcompat.app.AlertDialog
import androidx.core.widget.doAfterTextChanged
import com.ichi2.anki.dialogs.DiscardChangesDialog
import com.ichi2.utils.message
import com.ichi2.utils.negativeButton
Expand All @@ -41,6 +44,14 @@ class CardTemplateBrowserAppearanceEditor : AnkiActivity() {
private lateinit var questionEditText: EditText
private lateinit var answerEditText: EditText

// start with the callback disabled as there aren't any changes yet
private val discardChangesCallback =
object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() {
showDiscardChangesDialog()
}
}

override fun onCreate(savedInstanceState: Bundle?) {
if (showedActivityFailedScreen(savedInstanceState)) {
return
Expand All @@ -53,6 +64,15 @@ class CardTemplateBrowserAppearanceEditor : AnkiActivity() {
return
}
initializeUiFromBundle(bundle)
// default result, only changed to RESULT_OK if actually saving changes
setResult(RESULT_CANCELED)
onBackPressedDispatcher.addCallback(discardChangesCallback)
questionEditText.doAfterTextChanged { _ ->
discardChangesCallback.isEnabled = hasChanges()
}
answerEditText.doAfterTextChanged { _ ->
discardChangesCallback.isEnabled = hasChanges()
}
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
Expand All @@ -74,34 +94,22 @@ class CardTemplateBrowserAppearanceEditor : AnkiActivity() {
}
android.R.id.home -> {
Timber.i("Back Pressed")
closeWithDiscardWarning()
if (hasChanges()) {
showDiscardChangesDialog()
} else {
finish() // the result was already set to RESULT_CANCELLED
}
return true
}
else -> {}
}
return super.onOptionsItemSelected(item)
}

@Suppress("DEPRECATION", "Deprecated in API34+dependencies for predictive back feature")
@Deprecated("Deprecated in Java")
override fun onBackPressed() {
Timber.i("Back Button Pressed")
super.onBackPressed()
closeWithDiscardWarning()
}

private fun closeWithDiscardWarning() {
if (hasChanges()) {
Timber.i("Changes detected - displaying discard warning dialog")
showDiscardChangesDialog()
} else {
discardChangesAndClose()
}
}

private fun showDiscardChangesDialog() {
DiscardChangesDialog.showDialog(this) {
discardChangesAndClose()
Timber.i("Changes discarded, finishing...")
finish()
}
}

Expand Down Expand Up @@ -130,6 +138,8 @@ class CardTemplateBrowserAppearanceEditor : AnkiActivity() {
answerEditText = findViewById(R.id.answer_format)
answerEditText.setText(bundle.getString(INTENT_ANSWER_FORMAT))

discardChangesCallback.isEnabled = hasChanges()

enableToolbar()
setTitle(R.string.card_template_browser_appearance_title)
}
Expand All @@ -152,12 +162,6 @@ class CardTemplateBrowserAppearanceEditor : AnkiActivity() {
saveAndExit()
}

private fun discardChangesAndClose() {
Timber.i("Closing and discarding changes")
setResult(RESULT_CANCELED)
finish()
}

private fun saveAndExit() {
Timber.i("Save and Exit")
val data =
Expand Down
22 changes: 10 additions & 12 deletions AnkiDroid/src/main/java/com/ichi2/anki/NavigationDrawerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.LayoutRes
import androidx.annotation.VisibleForTesting
Expand Down Expand Up @@ -143,6 +144,13 @@ abstract class NavigationDrawerActivity :
// Decide which action to take when the navigation button is tapped.
toolbar.setNavigationOnClickListener { onNavigationPressed() }
}
val drawerBackCallback =
object : OnBackPressedCallback(isDrawerOpen) {
override fun handleOnBackPressed() {
closeDrawer()
}
}
onBackPressedDispatcher.addCallback(drawerBackCallback)
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
drawerToggle =
Expand All @@ -155,7 +163,7 @@ abstract class NavigationDrawerActivity :
override fun onDrawerClosed(drawerView: View) {
super.onDrawerClosed(drawerView)
invalidateOptionsMenu()

drawerBackCallback.isEnabled = false
// If animations are disabled, this is executed before onNavigationItemSelected is called
// PERF: May be able to reduce this delay
HandlerUtils.postDelayedOnNewHandler({
Expand All @@ -169,6 +177,7 @@ abstract class NavigationDrawerActivity :
override fun onDrawerOpened(drawerView: View) {
super.onDrawerOpened(drawerView)
invalidateOptionsMenu()
drawerBackCallback.isEnabled = true
}
}
if (drawerLayout is ClosableDrawerLayout) {
Expand Down Expand Up @@ -266,17 +275,6 @@ abstract class NavigationDrawerActivity :
}
}

@Suppress("deprecation") // onBackPressed
@Deprecated("Deprecated in Java")
override fun onBackPressed() {
if (isDrawerOpen) {
Timber.i("Back key pressed")
closeDrawer()
} else {
super.onBackPressed()
}
}

/**
* Called, when navigation button of the action bar is pressed.
* Design pattern: template method. Subclasses can override this to define their own behaviour.
Expand Down
60 changes: 17 additions & 43 deletions AnkiDroid/src/main/java/com/ichi2/anki/SharedDecksActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
Expand All @@ -55,6 +56,12 @@ class SharedDecksActivity : AnkiActivity() {
private var shouldHistoryBeCleared = false

private val allowedHosts = listOf(Regex("""^(?:.*\.)?ankiweb\.net$"""), Regex("""^ankiuser\.net$"""), Regex("""^ankisrs\.net$"""))
private val onBackPressedCallback =
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (webView.canGoBack()) webView.goBack()
}
}

/**
* Handle condition when page finishes loading and history needs to be cleared.
Expand All @@ -67,6 +74,15 @@ class SharedDecksActivity : AnkiActivity() {
object : WebViewClient() {
private var redirectTimes = 0

override fun doUpdateVisitedHistory(
view: WebView?,
url: String?,
isReload: Boolean,
) {
super.doUpdateVisitedHistory(view, url, isReload)
onBackPressedCallback.isEnabled = webView.canGoBack()
}

override fun onPageFinished(
view: WebView?,
url: String?,
Expand Down Expand Up @@ -240,49 +256,7 @@ class SharedDecksActivity : AnkiActivity() {
}

webView.webViewClient = webViewClient
}

/**
* If download screen is open:
* If download is in progress: Show download cancellation dialog
* If download is not in progress: Close the download screen
* If user can go back in WebView, navigate to previous webpage.
* Otherwise, close the WebView.
*/
@Deprecated("Deprecated in Java")
@Suppress("deprecation") // onBackPressed
override fun onBackPressed() {
when {
sharedDecksDownloadFragmentExists() -> {
supportFragmentManager.findFragmentByTag(SHARED_DECKS_DOWNLOAD_FRAGMENT)?.let {
if ((it as SharedDecksDownloadFragment).isDownloadInProgress) {
Timber.i("Back pressed when download is in progress, show cancellation confirmation dialog")
// Show cancel confirmation dialog if download is in progress
it.showCancelConfirmationDialog()
} else {
Timber.i("Back pressed when download is not in progress but download screen is open, close fragment")
// Remove fragment
supportFragmentManager.commit {
remove(it)
}
}
}
supportFragmentManager.popBackStackImmediate()
}
webView.canGoBack() -> {
Timber.i("Back pressed when user can navigate back to other webpages inside WebView")
webView.goBack()
}
else -> {
Timber.i("Back pressed which would lead to closing of the WebView")
super.onBackPressed()
}
}
}

private fun sharedDecksDownloadFragmentExists(): Boolean {
val sharedDecksDownloadFragment = supportFragmentManager.findFragmentByTag(SHARED_DECKS_DOWNLOAD_FRAGMENT)
return sharedDecksDownloadFragment != null && sharedDecksDownloadFragment.isAdded
onBackPressedDispatcher.addCallback(onBackPressedCallback)
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import android.webkit.CookieManager
import android.widget.Button
import android.widget.ProgressBar
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
Expand Down Expand Up @@ -82,6 +83,12 @@ class SharedDecksDownloadFragment : Fragment(R.layout.fragment_shared_decks_down
var isDownloadInProgress = false

private var downloadCancelConfirmationDialog: AlertDialog? = null
private val onBackPressedCallback =
object : OnBackPressedCallback(isDownloadInProgress) {
override fun handleOnBackPressed() {
showCancelConfirmationDialog()
}
}

companion object {
const val DOWNLOAD_PROGRESS_CHECK_DELAY = 1000L
Expand Down Expand Up @@ -136,6 +143,7 @@ class SharedDecksDownloadFragment : Fragment(R.layout.fragment_shared_decks_down
cancelButton.visibility = View.VISIBLE
tryAgainButton.visibility = View.GONE
}
requireActivity().onBackPressedDispatcher.addCallback(onBackPressedCallback)
}

/**
Expand Down Expand Up @@ -172,6 +180,7 @@ class SharedDecksDownloadFragment : Fragment(R.layout.fragment_shared_decks_down
downloadId = downloadManager.enqueue(downloadRequest)
fileName = currentFileName
isDownloadInProgress = true
onBackPressedCallback.isEnabled = isDownloadInProgress
Timber.d("Download ID -> $downloadId")
Timber.d("File name -> $fileName")
view?.findViewById<TextView>(R.id.downloading_title)?.text = getString(R.string.downloading_file, fileName)
Expand Down Expand Up @@ -484,21 +493,22 @@ class SharedDecksDownloadFragment : Fragment(R.layout.fragment_shared_decks_down

unregisterReceiver()
isDownloadInProgress = false
onBackPressedCallback.isEnabled = isDownloadInProgress

// If the cancel confirmation dialog is being shown and the download is no longer in progress, then remove the dialog.
removeCancelConfirmationDialog()
}

@Suppress("deprecation") // onBackPressed
fun showCancelConfirmationDialog() {
private fun showCancelConfirmationDialog() {
downloadCancelConfirmationDialog =
AlertDialog.Builder(requireContext()).create {
setTitle(R.string.cancel_download_question_title)
setPositiveButton(R.string.dialog_yes) { _, _ ->
downloadManager.remove(downloadId)
unregisterReceiver()
isDownloadInProgress = false
activity?.onBackPressed()
onBackPressedCallback.isEnabled = isDownloadInProgress
activity?.onBackPressedDispatcher?.onBackPressed()
}
setNegativeButton(R.string.dialog_no) { _, _ ->
downloadCancelConfirmationDialog?.dismiss()
Expand Down
18 changes: 2 additions & 16 deletions AnkiDroid/src/main/java/com/ichi2/anki/StudyOptionsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import com.ichi2.ui.RtlCompliantActionProvider
import com.ichi2.utils.ExtendedFragmentFactory
import com.ichi2.widget.WidgetStatus
import kotlinx.coroutines.launch
import timber.log.Timber

class StudyOptionsActivity :
AnkiActivity(),
Expand All @@ -53,6 +52,7 @@ class StudyOptionsActivity :
if (savedInstanceState == null) {
loadStudyOptionsFragment()
}
setResult(RESULT_OK)
}

private fun loadStudyOptionsFragment() {
Expand Down Expand Up @@ -83,7 +83,7 @@ class StudyOptionsActivity :
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
closeStudyOptions()
onBackPressedDispatcher.onBackPressed()
true
}
R.id.action_undo -> {
Expand All @@ -101,20 +101,6 @@ class StudyOptionsActivity :
}
}

private fun closeStudyOptions(result: Int = RESULT_OK) {
// mCompat.invalidateOptionsMenu(this);
setResult(result)
finish()
}

@Deprecated("Deprecated in Java")
override fun onBackPressed() {
Timber.i("Back key pressed")
closeStudyOptions()
@Suppress("DEPRECATION")
super.onBackPressed()
}

override fun onResume() {
super.onResume()
refreshUndoState()
Expand Down