Skip to content

Commit 9eac988

Browse files
Fix: Implements double tap back in whiteboard
1 parent e6a8f14 commit 9eac988

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

AnkiDroid/src/main/java/com/ichi2/anki/android/back/ExitViaDoubleTapBackBackPressCallback.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,31 @@ import com.ichi2.anki.snackbar.showSnackbar
2929
import com.ichi2.utils.HandlerUtils
3030
import timber.log.Timber
3131

32+
/**
33+
* Creates an [OnBackPressedCallback] that requires two back presses to exit.
34+
* On first press, [onFirstBack] is called and the callback is temporarily disabled
35+
* for 2s. If back is pressed again within that window,
36+
* it goes through normally. After the timeout, re-enables if [shouldReEnable] returns true.
37+
*
38+
* @param enabled initial enabled state
39+
* @param onFirstBack action on first back press (typically show a snackbar)
40+
* @param shouldReEnable condition checked after timeout to decide whether to re-enable
41+
*/
42+
fun doubleBackPressCallback(
43+
enabled: Boolean,
44+
onFirstBack: () -> Unit,
45+
shouldReEnable: () -> Boolean = { true },
46+
): OnBackPressedCallback =
47+
object : OnBackPressedCallback(enabled) {
48+
override fun handleOnBackPressed() {
49+
onFirstBack()
50+
isEnabled = false
51+
HandlerUtils.executeFunctionWithDelay(Consts.SHORT_TOAST_DURATION) {
52+
isEnabled = shouldReEnable()
53+
}
54+
}
55+
}
56+
3257
/**
3358
* Note: this uses sharedPreferences via AnkiDroidApp, so must be called after
3459
* [AnkiActivity.showedActivityFailedScreen]

AnkiDroid/src/main/java/com/ichi2/anki/ui/windows/reviewer/ReviewerFragment.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,12 @@ import androidx.lifecycle.flowWithLifecycle
4949
import androidx.lifecycle.lifecycleScope
5050
import androidx.lifecycle.repeatOnLifecycle
5151
import anki.scheduler.CardAnswer.Rating
52+
import com.google.android.material.snackbar.Snackbar
5253
import com.ichi2.anki.CollectionManager
5354
import com.ichi2.anki.DispatchKeyEventListener
5455
import com.ichi2.anki.Flag
5556
import com.ichi2.anki.R
57+
import com.ichi2.anki.android.back.doubleBackPressCallback
5658
import com.ichi2.anki.cardviewer.Gesture
5759
import com.ichi2.anki.common.annotations.NeedsTest
5860
import com.ichi2.anki.common.utils.android.isRobolectric
@@ -163,8 +165,22 @@ class ReviewerFragment :
163165
) {
164166
super.onViewCreated(view, savedInstanceState)
165167

168+
val doubleBackCallback =
169+
doubleBackPressCallback(
170+
enabled = false,
171+
onFirstBack = { showSnackbar(R.string.back_pressed_once, Snackbar.LENGTH_SHORT) },
172+
shouldReEnable = { viewModel.whiteboardEnabledFlow.value },
173+
)
174+
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, doubleBackCallback)
175+
176+
viewModel.whiteboardEnabledFlow
177+
.flowWithLifecycle(lifecycle)
178+
.collectIn(lifecycleScope) { isWhiteboardEnabled ->
179+
doubleBackCallback.isEnabled = isWhiteboardEnabled
180+
}
181+
166182
binding.backButton.setOnClickListener {
167-
requireActivity().finish()
183+
requireActivity().onBackPressedDispatcher.onBackPressed()
168184
}
169185

170186
setupBindings()

0 commit comments

Comments
 (0)