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 @@ -74,6 +74,12 @@ enum class ViewerAction(
ADD_NOTE(R.id.action_add_note, R.drawable.ic_add, R.string.menu_add_note, DISABLED),
TAG(R.id.action_edit_tags, R.drawable.ic_tag, R.string.menu_edit_tags, DISABLED),
RESCHEDULE_NOTE(R.id.action_set_due_date, R.drawable.ic_reschedule, titleRes = R.string.empty_string, DISABLED),
RESET_PROGRESS(
R.id.action_reset_progress,
drawableRes = R.drawable.ic_backup_restore,
titleRes = R.string.card_editor_reset_card,
DISABLED,
),
TOGGLE_AUTO_ADVANCE(R.id.action_toggle_auto_advance, R.drawable.ic_fast_forward, R.string.toggle_auto_advance, DISABLED),
RECORD_VOICE(R.id.action_record_voice, R.drawable.ic_action_mic, R.string.record_voice, DISABLED),
PLAY_MEDIA(R.id.action_replay_media, R.drawable.ic_play_circle_white, R.string.replay_media, DISABLED),
Expand Down Expand Up @@ -149,6 +155,7 @@ enum class ViewerAction(
STATISTICS -> listOf(keycode(KeyEvent.KEYCODE_T))
PLAY_MEDIA -> listOf(keycode(KeyEvent.KEYCODE_R))
PREVIOUS_CARD_INFO -> listOf(keycode(KeyEvent.KEYCODE_I, ModifierKeys(shift = false, ctrl = true, alt = true)))
RESET_PROGRESS -> listOf(keycode(KeyEvent.KEYCODE_N, ModifierKeys(ctrl = true, alt = true, shift = false)))
TOGGLE_FLAG_RED ->
listOf(
keycode(KeyEvent.KEYCODE_1, ctrl()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import android.os.Bundle
import androidx.core.content.edit
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.setFragmentResultListener
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.ichi2.anki.AnkiActivity
import com.ichi2.anki.CollectionManager.TR
import com.ichi2.anki.R
import com.ichi2.anki.common.annotations.NeedsTest
Expand Down Expand Up @@ -155,7 +157,7 @@ class ForgetCardsDialog : DialogFragment() {
*
* @param cardsIdsProducer lambda which returns the list of cards for which to reset the progress
*/
internal fun AnkiActivity.registerOnForgetHandler(cardsIdsProducer: suspend () -> List<CardId>) {
internal fun FragmentActivity.registerOnForgetHandler(cardsIdsProducer: suspend () -> List<CardId>) {
setFragmentResultListener(ForgetCardsDialog.REQUEST_KEY_FORGET) { _, bundle ->
forgetCards(
cardsIdsProducer = cardsIdsProducer,
Expand All @@ -165,7 +167,23 @@ internal fun AnkiActivity.registerOnForgetHandler(cardsIdsProducer: suspend () -
}
}

private fun AnkiActivity.forgetCards(
/**
* Listen for requests from [ForgetCardsDialog] and triggers backend calls to reset progress for
* current selected/reviewed card/cards. Callers need to supply the list of cards ids.
*
* @param cardsIdsProducer lambda which returns the list of cards for which to reset the progress
*/
internal fun Fragment.registerOnForgetHandler(cardsIdsProducer: suspend () -> List<CardId>) {
Comment thread
david-allison marked this conversation as resolved.
setFragmentResultListener(ForgetCardsDialog.REQUEST_KEY_FORGET) { _, bundle ->
activity?.forgetCards(
cardsIdsProducer = cardsIdsProducer,
restoreOriginalPositionIfPossible = bundle.getBoolean(ForgetCardsDialog.ARG_RESTORE_ORIGINAL),
resetRepetitionAndLapseCounts = bundle.getBoolean(ForgetCardsDialog.ARG_RESET_REPETITION),
)
}
}

private fun FragmentActivity.forgetCards(
cardsIdsProducer: suspend () -> List<CardId>,
restoreOriginalPositionIfPossible: Boolean,
resetRepetitionAndLapseCounts: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ import com.ichi2.anki.previewer.setFrameStyle
import com.ichi2.anki.previewer.stdHtml
import com.ichi2.anki.reviewer.BindingMap
import com.ichi2.anki.reviewer.ReviewerBinding
import com.ichi2.anki.scheduling.ForgetCardsDialog
import com.ichi2.anki.scheduling.SetDueDateDialog
import com.ichi2.anki.scheduling.registerOnForgetHandler
import com.ichi2.anki.settings.Prefs
import com.ichi2.anki.settings.enums.FrameStyle
import com.ichi2.anki.settings.enums.HideSystemBars
Expand All @@ -94,6 +96,8 @@ import com.squareup.seismic.ShakeDetector
import dev.androidbroadcast.vbpd.viewBinding
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import timber.log.Timber
import kotlin.math.max
Expand Down Expand Up @@ -176,6 +180,7 @@ class ReviewerFragment :
setupToolbarPosition()
setupAnswerTimer()
setupMargins()
setupResetProgress()
setupCheckPronunciation()
setupActions()
setupWhiteboard()
Expand Down Expand Up @@ -499,6 +504,17 @@ class ReviewerFragment :
}
}

private fun setupResetProgress() {
viewModel.resetProgressFlow
.flowWithLifecycle(lifecycle)
.onEach {
showDialogFragment(ForgetCardsDialog())
}.launchIn(lifecycleScope)
// TODO handle 'Reset progress' in the ViewModel instead of the activity, once
// a mechanism of showing a progress bar if the operation takes too long is implemented
Comment on lines +513 to +514
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

registerOnForgetHandler { listOf(viewModel.getCardId()) }
}

private fun setupCheckPronunciation() {
viewModel.voiceRecorderEnabledFlow.flowWithLifecycle(lifecycle).collectIn(lifecycleScope) { isEnabled ->
if (isEnabled && binding.checkPronunciationContainer.getFragment<CheckPronunciationFragment?>() == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class ReviewerViewModel(
val destinationFlow = MutableSharedFlow<Destination>()
val editNoteTagsFlow = MutableSharedFlow<NoteId>()
val setDueDateFlow = MutableSharedFlow<CardId>()
val resetProgressFlow = MutableSharedFlow<Unit>()
val answerFeedbackFlow = MutableSharedFlow<Rating>()
val voiceRecorderEnabledFlow = MutableStateFlow(false)
val whiteboardEnabledFlow = MutableStateFlow(repository.isWhiteboardEnabled)
Expand Down Expand Up @@ -200,6 +201,8 @@ class ReviewerViewModel(
executeAction(action)
}

suspend fun getCardId() = currentCard.await().id

/**
* Sends an [eval] request to load the card answer, and updates components
* with behavior specific to the `Answer` card side.
Expand Down Expand Up @@ -659,6 +662,8 @@ class ReviewerViewModel(
setDueDateFlow.emit(cardId)
}

private suspend fun launchResetProgress() = resetProgressFlow.emit(Unit)

private suspend fun setupAnswerTimer(card: Card) {
val shouldShowTimer = withCol { card.shouldShowTimer(this@withCol) }
val limitMs = withCol { card.timeLimit(this@withCol) }
Expand Down Expand Up @@ -692,6 +697,7 @@ class ReviewerViewModel(
ViewerAction.REDO -> redo()
ViewerAction.UNDO -> undo()
ViewerAction.RESCHEDULE_NOTE -> launchSetDueDate()
ViewerAction.RESET_PROGRESS -> launchResetProgress()
ViewerAction.TOGGLE_AUTO_ADVANCE -> toggleAutoAdvance()
ViewerAction.BURY_NOTE -> buryNote()
ViewerAction.BURY_CARD -> buryCard()
Expand Down
1 change: 1 addition & 0 deletions AnkiDroid/src/main/res/values/ids.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
<item type="id" name="action_record_voice"/>
<item type="id" name="action_replay_media"/>
<item type="id" name="action_set_due_date"/>
<item type="id" name="action_reset_progress"/>
<item type="id" name="action_browse"/>
<item type="id" name="action_statistics"/>

Expand Down
Loading