Skip to content

Commit 545a450

Browse files
committed
feat(controls): add "flip and answer" option
1 parent 1fe1e54 commit 545a450

File tree

3 files changed

+69
-10
lines changed

3 files changed

+69
-10
lines changed

AnkiDroid/src/main/java/com/ichi2/anki/preferences/ControlsSettingsFragment.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.ichi2.anki.preferences
1818
import android.content.res.Configuration
1919
import androidx.annotation.StringRes
2020
import androidx.annotation.XmlRes
21+
import androidx.appcompat.app.AlertDialog
2122
import androidx.lifecycle.lifecycleScope
2223
import androidx.lifecycle.withResumed
2324
import androidx.lifecycle.withStarted
@@ -31,12 +32,15 @@ import com.ichi2.anki.cardviewer.ViewerCommand
3132
import com.ichi2.anki.common.annotations.NeedsTest
3233
import com.ichi2.anki.preferences.reviewer.ViewerAction
3334
import com.ichi2.anki.previewer.PreviewerAction
35+
import com.ichi2.anki.reviewer.CardSide
3436
import com.ichi2.anki.reviewer.MappableAction
3537
import com.ichi2.anki.reviewer.MappableBinding.Companion.toPreferenceString
3638
import com.ichi2.anki.settings.Prefs
3739
import com.ichi2.anki.ui.internationalization.toSentenceCase
3840
import com.ichi2.anki.utils.ext.sharedPrefs
3941
import com.ichi2.preferences.ControlPreference
42+
import com.ichi2.preferences.ReviewerControlPreference
43+
import com.ichi2.utils.show
4044
import kotlinx.coroutines.launch
4145
import timber.log.Timber
4246

@@ -64,6 +68,7 @@ class ControlsSettingsFragment :
6468
setControlPreferencesDefaultValues(initialScreen)
6569
setDynamicTitle()
6670
setupNewStudyScreenSettings()
71+
setupAnswerCommands()
6772
}
6873

6974
/**
@@ -198,6 +203,43 @@ class ControlsSettingsFragment :
198203
}
199204
}
200205

206+
private fun setupAnswerCommands() {
207+
val showAnswerPref = (findPreference<ControlPreference>(R.string.show_answer_command_key) as? ReviewerControlPreference)
208+
209+
val answerCommandKeys =
210+
listOf(
211+
ViewerAction.ANSWER_AGAIN.preferenceKey,
212+
ViewerAction.ANSWER_HARD.preferenceKey,
213+
ViewerAction.ANSWER_GOOD.preferenceKey,
214+
ViewerAction.ANSWER_EASY.preferenceKey,
215+
)
216+
for (key in answerCommandKeys) {
217+
(findPreference<Preference>(key) as? ReviewerControlPreference)?.let { answerPref ->
218+
val items =
219+
arrayOf(
220+
getString(R.string.only_answer),
221+
getString(R.string.flip_and_answer),
222+
)
223+
answerPref.setOnBindingSelectedListener { binding ->
224+
AlertDialog.Builder(requireContext()).show {
225+
setTitle(answerPref.title)
226+
setIcon(answerPref.icon)
227+
setItems(items) { _, index ->
228+
when (index) {
229+
0 -> answerPref.addBinding(binding, CardSide.ANSWER)
230+
1 -> {
231+
answerPref.addBinding(binding, CardSide.ANSWER)
232+
showAnswerPref?.addBinding(binding, CardSide.QUESTION)
233+
}
234+
}
235+
}
236+
}
237+
true
238+
}
239+
}
240+
}
241+
}
242+
201243
companion object {
202244
private val actionToScreenMap: Map<String, ControlPreferenceScreen> by lazy {
203245
ControlPreferenceScreen.entries

AnkiDroid/src/main/java/com/ichi2/preferences/ReviewerControlPreference.kt

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,25 +69,38 @@ class ReviewerControlPreference : ControlPreference {
6969

7070
override fun getMappableBindings(): List<ReviewerBinding> = ReviewerBinding.fromPreferenceString(value).toList()
7171

72-
override fun onKeySelected(binding: Binding) {
73-
selectSide { side ->
74-
addBinding(binding, side)
75-
}
72+
fun interface OnBindingSelectedListener {
73+
/**
74+
* Called when a binding is selected, before the side is set. This allows listeners
75+
* to respond before the value is set, and potentially override it.
76+
*
77+
* @param binding The selected binding.
78+
*
79+
* @return True if the listener has consumed the event, false otherwise.
80+
*/
81+
fun onBindingSelected(binding: Binding): Boolean
7682
}
7783

78-
override fun onGestureSelected(binding: Binding) {
79-
selectSide { side ->
80-
addBinding(binding, side)
81-
}
84+
private var onBindingSelectedListener: OnBindingSelectedListener? = null
85+
86+
fun setOnBindingSelectedListener(listener: OnBindingSelectedListener) {
87+
onBindingSelectedListener = listener
8288
}
8389

84-
override fun onAxisSelected(binding: Binding) {
90+
override fun onKeySelected(binding: Binding) = setBinding(binding)
91+
92+
override fun onGestureSelected(binding: Binding) = setBinding(binding)
93+
94+
override fun onAxisSelected(binding: Binding) = setBinding(binding)
95+
96+
fun setBinding(binding: Binding) {
97+
if (onBindingSelectedListener?.onBindingSelected(binding) == true) return
8598
selectSide { side ->
8699
addBinding(binding, side)
87100
}
88101
}
89102

90-
private fun addBinding(
103+
fun addBinding(
91104
binding: Binding,
92105
side: CardSide,
93106
) {

AnkiDroid/src/main/res/values/10-preferences.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,10 @@ this formatter is used if the bind only applies to the answer">A: %s</string>
470470
><![CDATA[Improved study screen that will succeed the current one. Some features of the old screen have been changed or removed. Please report any <a href="%1$s">feedback</a> or <a href="%2$s">bugs</a>.]]></string>
471471
<string name="show_answer_feedback" maxLength="41">Show answer feedback</string>
472472
<string name="screen" maxLength="41">Screen</string>
473+
<string name="only_answer" maxLength="41" comment="Configuration of the 'Answer' commands to only answer the card"
474+
>Only answer</string>
475+
<string name="flip_and_answer" maxLength="41" comment="Configuration of the 'Answer' commands to answer the card if on the answer side, and flip it if on the question side"
476+
>Flip and answer</string>
473477

474478
<!--Keyboard shortcuts dialog-->
475479
<string name="open_settings" comment="Description of the shortcut that opens the app settings">Open settings</string>

0 commit comments

Comments
 (0)