Skip to content

Commit 87942d7

Browse files
lukstbitmikehardy
authored andcommitted
Add 'Previous card info' menu action in new reviewer
1 parent a02327e commit 87942d7

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

AnkiDroid/src/main/java/com/ichi2/anki/preferences/reviewer/ViewerAction.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ enum class ViewerAction(
6969
STATISTICS(R.id.action_statistics, R.drawable.ic_bar_chart_black, R.string.empty_string, DISABLED),
7070
DECK_OPTIONS(R.id.action_deck_options, R.drawable.ic_tune_white, R.string.menu__deck_options, DISABLED),
7171
CARD_INFO(R.id.action_card_info, R.drawable.ic_dialog_info, R.string.card_info_title, DISABLED),
72+
PREVIOUS_CARD_INFO(R.id.action_previous_card_info, R.drawable.ic_outline_info_24, R.string.empty_string, DISABLED),
7273
ADD_NOTE(R.id.action_add_note, R.drawable.ic_add, R.string.menu_add_note, DISABLED),
7374
TAG(R.id.action_edit_tags, R.drawable.ic_tag, R.string.menu_edit_tags, DISABLED),
7475
RESCHEDULE_NOTE(R.id.action_set_due_date, R.drawable.ic_reschedule, titleRes = R.string.empty_string, DISABLED),
@@ -144,6 +145,7 @@ enum class ViewerAction(
144145
BROWSE -> listOf(keycode(KeyEvent.KEYCODE_B))
145146
STATISTICS -> listOf(keycode(KeyEvent.KEYCODE_T))
146147
PLAY_MEDIA -> listOf(keycode(KeyEvent.KEYCODE_R))
148+
PREVIOUS_CARD_INFO -> listOf(keycode(KeyEvent.KEYCODE_I, ModifierKeys(shift = false, ctrl = true, alt = true)))
147149
TOGGLE_FLAG_RED ->
148150
listOf(
149151
keycode(KeyEvent.KEYCODE_1, ctrl()),
@@ -248,6 +250,7 @@ enum class ViewerAction(
248250
BROWSE -> TR.qtMiscBrowse()
249251
STATISTICS -> TR.statisticsTitle()
250252
RESCHEDULE_NOTE -> TR.actionsSetDueDate().toSentenceCase(context, R.string.sentence_set_due_date)
253+
PREVIOUS_CARD_INFO -> TR.actionsPreviousCardInfo().toSentenceCase(context, R.string.sentence_actions_previous_card_info)
251254
else -> context.getString(titleRes)
252255
}
253256

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616
package com.ichi2.anki.ui.windows.reviewer
1717

18+
import androidx.lifecycle.SavedStateHandle
1819
import anki.collection.OpChanges
1920
import anki.collection.OpChangesAfterUndo
2021
import anki.frontend.SetSchedulingStatesRequest
@@ -63,6 +64,7 @@ import com.ichi2.anki.ui.windows.reviewer.autoadvance.AutoAdvance
6364
import com.ichi2.anki.utils.CollectionPreferences
6465
import com.ichi2.anki.utils.Destination
6566
import com.ichi2.anki.utils.ext.answerCard
67+
import com.ichi2.anki.utils.ext.cardStatsNoCardClean
6668
import com.ichi2.anki.utils.ext.flag
6769
import com.ichi2.anki.utils.ext.getLongOrNull
6870
import com.ichi2.anki.utils.ext.setUserFlagForCards
@@ -74,8 +76,9 @@ import kotlinx.coroutines.flow.MutableStateFlow
7476
import org.intellij.lang.annotations.Language
7577
import timber.log.Timber
7678

77-
class ReviewerViewModel :
78-
CardViewerViewModel(),
79+
class ReviewerViewModel(
80+
val savedStateHandle: SavedStateHandle,
81+
) : CardViewerViewModel(),
7982
ChangeManager.Subscriber,
8083
BindingProcessor<ReviewerBinding, ViewerAction> {
8184
private var queueState: Deferred<CurrentQueueState?> =
@@ -251,6 +254,18 @@ class ReviewerViewModel :
251254
destinationFlow.emit(destination)
252255
}
253256

257+
private suspend fun emitPreviousCardInfoDestination() {
258+
val previousCardId: CardId? = savedStateHandle.getLongOrNull(KEY_PREVIOUS_CARD_ID)
259+
if (previousCardId == null) {
260+
Timber.i("No previous answered card found, ignoring request for 'previous card info'")
261+
actionFeedbackFlow.emit(TR.cardStatsNoCardClean())
262+
return
263+
}
264+
val destination = CardInfoDestination(previousCardId, TR.cardStatsPreviousCard(TR.decksStudy()))
265+
Timber.i("Launching 'previous card info' for card %d", previousCardId)
266+
destinationFlow.emit(destination)
267+
}
268+
254269
private suspend fun emitDeckOptionsDestination() {
255270
val deckId = withCol { decks.getCurrentId() }
256271
val isFiltered = withCol { decks.isFiltered(deckId) }
@@ -464,6 +479,7 @@ class ReviewerViewModel :
464479

465480
undoableOp(handler = this) { sched.answerCard(answer) }
466481
answerFeedbackFlow.emit(rating)
482+
savedStateHandle[KEY_PREVIOUS_CARD_ID] = card.id
467483

468484
val wasLeech = withCol { sched.stateIsLeech(answer.newState) }
469485
if (wasLeech) {
@@ -640,6 +656,7 @@ class ReviewerViewModel :
640656
when (action) {
641657
ViewerAction.ADD_NOTE -> emitAddNoteDestination()
642658
ViewerAction.CARD_INFO -> emitCardInfoDestination()
659+
ViewerAction.PREVIOUS_CARD_INFO -> emitPreviousCardInfoDestination()
643660
ViewerAction.DECK_OPTIONS -> emitDeckOptionsDestination()
644661
ViewerAction.EDIT -> emitEditNoteDestination()
645662
ViewerAction.TAG -> editNoteTags()
@@ -740,4 +757,8 @@ class ReviewerViewModel :
740757
}
741758
}
742759
}
760+
761+
companion object {
762+
private const val KEY_PREVIOUS_CARD_ID = "key_previous_card_id"
763+
}
743764
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/****************************************************************************************
2+
* Copyright (c) 2025 lukstbit <[email protected]> *
3+
* *
4+
* This program is free software; you can redistribute it and/or modify it under *
5+
* the terms of the GNU General Public License as published by the Free Software *
6+
* Foundation; either version 3 of the License, or (at your option) any later *
7+
* version. *
8+
* *
9+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY *
10+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
11+
* PARTICULAR PURPOSE. See the GNU General Public License for more details. *
12+
* *
13+
* You should have received a copy of the GNU General Public License along with *
14+
* this program. If not, see <http://www.gnu.org/licenses/>. *
15+
****************************************************************************************/
16+
package com.ichi2.anki.utils.ext
17+
18+
import net.ankiweb.rsdroid.Translations
19+
20+
/**
21+
* Same as [Translations.cardStatsNoCard] but removes unwanted characters like parentheses and dots
22+
* from the returned string:
23+
*
24+
* Original string: "(No card to display.)" -> Returned: "No card to display"
25+
*/
26+
fun Translations.cardStatsNoCardClean(): String {
27+
// regex removes any parentheses or dots from the string
28+
return cardStatsNoCard().replace("[().]".toRegex(), "")
29+
}

AnkiDroid/src/main/res/values/ids.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<item type="id" name="action_edit_note"/>
3535
<item type="id" name="action_edit_tags"/>
3636
<item type="id" name="action_card_info"/>
37+
<item type="id" name="action_previous_card_info"/>
3738
<item type="id" name="action_bury_card"/>
3839
<item type="id" name="action_bury_note"/>
3940
<item type="id" name="action_suspend_card"/>

0 commit comments

Comments
 (0)