Skip to content

Commit

Permalink
feat(new reviewer): undo and redo
Browse files Browse the repository at this point in the history
  • Loading branch information
BrayanDSO committed May 28, 2024
1 parent 6b2c686 commit 136f1c9
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.lifecycle.lifecycleScope
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.button.MaterialButton
import com.ichi2.anki.AbstractFlashcardViewer.Companion.RESULT_NO_MORE_CARDS
import com.ichi2.anki.CollectionManager
import com.ichi2.anki.Flag
import com.ichi2.anki.NoteEditor
import com.ichi2.anki.R
Expand Down Expand Up @@ -120,6 +121,7 @@ class ReviewerFragment :
R.id.action_edit -> launchEditNote()
R.id.action_mark -> viewModel.toggleMark()
R.id.action_open_deck_options -> launchDeckOptions()
R.id.action_redo -> viewModel.redo()
R.id.action_suspend_card -> viewModel.suspendCard()
R.id.action_suspend_note -> viewModel.suspendNote()
R.id.action_flag_zero -> viewModel.setFlag(Flag.NONE)
Expand All @@ -130,6 +132,7 @@ class ReviewerFragment :
R.id.action_flag_five -> viewModel.setFlag(Flag.PINK)
R.id.action_flag_six -> viewModel.setFlag(Flag.TURQUOISE)
R.id.action_flag_seven -> viewModel.setFlag(Flag.PURPLE)
R.id.action_undo -> viewModel.undo()
R.id.user_action_1 -> viewModel.userAction(1)
R.id.user_action_2 -> viewModel.userAction(2)
R.id.user_action_3 -> viewModel.userAction(3)
Expand Down Expand Up @@ -230,6 +233,20 @@ class ReviewerFragment :
.collectLatestIn(lifecycleScope) { flagCode ->
menu.findItem(R.id.action_flag).setIcon(Flag.fromCode(flagCode).drawableRes)
}

val undoItem = menu.findItem(R.id.action_undo)
viewModel.undoLabelFlow.flowWithLifecycle(lifecycle)
.collectLatestIn(lifecycleScope) { label ->
undoItem.title = label ?: CollectionManager.TR.undoUndo()
undoItem.isEnabled = label != null
}

val redoItem = menu.findItem(R.id.action_redo)
viewModel.redoLabelFlow.flowWithLifecycle(lifecycle)
.collectLatestIn(lifecycleScope) { label ->
redoItem.title = label ?: CollectionManager.TR.undoRedo()
redoItem.isEnabled = label != null
}
}

private val noteEditorLauncher =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import androidx.activity.result.ActivityResult
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import anki.collection.OpChanges
import anki.frontend.SetSchedulingStatesRequest
import com.ichi2.anki.CollectionManager
import com.ichi2.anki.CollectionManager.withCol
Expand All @@ -40,9 +41,12 @@ import com.ichi2.anki.servicelayer.MARKED_TAG
import com.ichi2.anki.servicelayer.NoteService
import com.ichi2.anki.servicelayer.isBuryNoteAvailable
import com.ichi2.anki.servicelayer.isSuspendNoteAvailable
import com.ichi2.libanki.ChangeManager
import com.ichi2.libanki.hasTag
import com.ichi2.libanki.note
import com.ichi2.libanki.redo
import com.ichi2.libanki.sched.CurrentQueueState
import com.ichi2.libanki.undo
import com.ichi2.libanki.undoableOp
import com.ichi2.libanki.utils.TimeManager
import kotlinx.coroutines.CompletableDeferred
Expand All @@ -53,7 +57,8 @@ import kotlinx.coroutines.flow.MutableStateFlow

class ReviewerViewModel(cardMediaPlayer: CardMediaPlayer) :
CardViewerViewModel(cardMediaPlayer),
PostRequestHandler {
PostRequestHandler,
ChangeManager.Subscriber {

private var queueState: Deferred<CurrentQueueState?> = asyncIO {
// this assumes that the Reviewer won't be launched if there isn't a queueState
Expand All @@ -68,6 +73,8 @@ class ReviewerViewModel(cardMediaPlayer: CardMediaPlayer) :
val actionFeedbackFlow = MutableSharedFlow<String>()
val canBuryNoteFlow = MutableStateFlow(true)
val canSuspendNoteFlow = MutableStateFlow(true)
val undoLabelFlow = MutableStateFlow<String?>(null)
val redoLabelFlow = MutableStateFlow<String?>(null)

private val server = AnkiServer(this).also { it.start() }
private val stateMutationKey = TimeManager.time.intTimeMS().toString()
Expand All @@ -88,6 +95,13 @@ class ReviewerViewModel(cardMediaPlayer: CardMediaPlayer) :
*/
private var statesMutated = true

init {
ChangeManager.subscribe(this)
launchCatchingIO {
updateUndoRedo()
}
}

/* *********************************************************************************************
************************ Public methods: meant to be used by the View **************************
********************************************************************************************* */
Expand Down Expand Up @@ -230,6 +244,34 @@ class ReviewerViewModel(cardMediaPlayer: CardMediaPlayer) :
}
}

fun undo() {
launchCatchingIO {
val changes = undoableOp(OpHandler.UNDO_REDO) {
undo()
}
val message = if (changes.operation.isEmpty()) {
CollectionManager.TR.actionsNothingToUndo()
} else {
CollectionManager.TR.undoActionUndone(changes.operation)
}
actionFeedbackFlow.emit(message)
}
}

fun redo() {
launchCatchingIO {
val changes = undoableOp(OpHandler.UNDO_REDO) {
redo()
}
val message = if (changes.operation.isEmpty()) {
CollectionManager.TR.actionsNothingToRedo()
} else {
CollectionManager.TR.undoRedoAction(changes.operation)
}
actionFeedbackFlow.emit(message)
}
}

fun userAction(@Reviewer.UserAction number: Int) {
launchCatchingIO {
eval.emit("javascript: ankidroid.userAction($number);")
Expand Down Expand Up @@ -339,6 +381,19 @@ class ReviewerViewModel(cardMediaPlayer: CardMediaPlayer) :
return text
}

private suspend fun updateUndoRedo() {
undoLabelFlow.emit(withCol { undoLabel() })
redoLabelFlow.emit(withCol { redoLabel() })
}

override fun opExecuted(changes: OpChanges, handler: Any?) {
launchCatchingIO { updateUndoRedo() }

if (handler == OpHandler.UNDO_REDO && (changes.card || changes.note)) {
launchCatchingIO { updateCurrentCard() }
}
}

companion object {
fun factory(soundPlayer: CardMediaPlayer): ViewModelProvider.Factory {
return viewModelFactory {
Expand All @@ -349,3 +404,7 @@ class ReviewerViewModel(cardMediaPlayer: CardMediaPlayer) :
}
}
}

private enum class OpHandler {
UNDO_REDO
}
12 changes: 12 additions & 0 deletions AnkiDroid/src/main/res/menu/reviewer2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="@+id/action_undo"
android:enabled="false"
android:icon="@drawable/ic_undo_white"
tools:title="Undo"
app:showAsAction="never"/>
<item
android:id="@+id/action_redo"
android:enabled="false"
android:icon="@drawable/ic_redo"
tools:title="Redo"
app:showAsAction="never"/>
<item
android:id="@+id/action_flag"
android:title="@string/menu_flag_card"
Expand Down

0 comments on commit 136f1c9

Please sign in to comment.