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
9 changes: 5 additions & 4 deletions AnkiDroid/src/main/assets/scripts/ankidroid.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ globalThis.ankidroid.showAllHints = function () {
};

/**
* @param {InputEvent} event - the oninput event of the type answer <input>
* @param {KeyboardEvent} event - the onkeydown event of the type answer <input>
*/
globalThis.ankidroid.onTypeAnswerInput = function (event) {
const encodedValue = encodeURIComponent(event.target.value);
window.location.href = `ankidroid://typeinput/${encodedValue}`;
globalThis.ankidroid.onTypeAnswerKeyDown = function (event) {
if (event.key === "Enter") {
window.location.href = `ankidroid://show-answer`;
}
};

document.addEventListener("focusin", event => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import androidx.core.view.WindowInsetsControllerCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.FragmentContainerView
import androidx.fragment.app.commit
import androidx.fragment.app.viewModels
Expand Down Expand Up @@ -208,7 +207,7 @@ class ReviewerFragment :
}
}

viewModel.statesMutationEval.collectIn(lifecycleScope) { eval ->
viewModel.statesMutationEvalFlow.collectIn(lifecycleScope) { eval ->
webView.evaluateJavascript(eval) {
viewModel.onStateMutationCallback()
}
Expand Down Expand Up @@ -288,7 +287,7 @@ class ReviewerFragment :
val typeAnswerContainer = view.findViewById<MaterialCardView>(R.id.type_answer_container)
val typeAnswerEditText =
view.findViewById<TextInputEditText>(R.id.type_answer_edit_text).apply {
setOnEditorActionListener { editTextView, actionId, _ ->
setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
viewModel.onShowAnswer()
return@setOnEditorActionListener true
Expand All @@ -303,11 +302,9 @@ class ReviewerFragment :
insetsController.hide(WindowInsetsCompat.Type.ime())
}
}
addTextChangedListener { editable ->
viewModel.typedAnswer = editable?.toString() ?: ""
}
}

val isHtmlTypeAnswerEnabled = Prefs.isHtmlTypeAnswerEnabled
lifecycleScope.launch {
val autoFocusTypeAnswer = Prefs.autoFocusTypeAnswer
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
Expand All @@ -317,7 +314,7 @@ class ReviewerFragment :
return@collect
}

if (Prefs.isHtmlTypeAnswerEnabled) {
if (isHtmlTypeAnswerEnabled) {
webView.requestFocus()
webView.evaluateJavascript("document.getElementById('typeans').focus();", null)
return@collect
Expand All @@ -341,6 +338,22 @@ class ReviewerFragment :
viewModel.onCardUpdatedFlow.flowWithLifecycle(lifecycle).collectIn(lifecycleScope) {
typeAnswerEditText.text = null
}

viewModel.onTypedAnswerResultFlow
.flowWithLifecycle(lifecycle)
.collectIn(lifecycleScope) { request ->
if (isHtmlTypeAnswerEnabled) {
val script = """document.getElementById("typeans").value;"""
webView.evaluateJavascript(script) { callback ->
// the retuned string comes with surrounding `"`, so remove it once
val typedAnswer = callback.removeSurrounding("\"")
request.complete(typedAnswer)
}
} else {
val typedAnswer = typeAnswerEditText.text.toString()
request.complete(typedAnswer)
}
}
}

/** Chooses the input type based on whether the expected answer is a number or text */
Expand Down Expand Up @@ -719,7 +732,7 @@ class ReviewerFragment :
when (url.host) {
"focusin" -> webviewHasFocus = true
"focusout" -> webviewHasFocus = false
"typeinput" -> url.path?.substring(1)?.let { viewModel.typedAnswer = it }
"show-answer" -> viewModel.onShowAnswer()
}
true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import kotlinx.coroutines.Deferred
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.withTimeoutOrNull
import org.intellij.lang.annotations.Language
import timber.log.Timber

Expand All @@ -96,6 +97,7 @@ class ReviewerViewModel :
val redoLabelFlow = MutableStateFlow<String?>(null)
val countsFlow = MutableStateFlow(Counts() to Counts.Queue.NEW)
val typeAnswerFlow = MutableStateFlow<TypeAnswer?>(null)
val onTypedAnswerResultFlow = MutableSharedFlow<CompletableDeferred<String>>()
val onCardUpdatedFlow = MutableSharedFlow<Unit>()
val destinationFlow = MutableSharedFlow<Destination>()
val editNoteTagsFlow = MutableSharedFlow<NoteId>()
Expand All @@ -106,11 +108,11 @@ class ReviewerViewModel :
val whiteboardEnabledFlow = MutableStateFlow(false)
val replayVoiceFlow = MutableSharedFlow<Unit>()
val timeBoxReachedFlow = MutableSharedFlow<Collection.TimeboxReached>()
val statesMutationEvalFlow = MutableSharedFlow<String>()

override val server: AnkiServer = AnkiServer(this, StudyScreenRepository.getServerPort()).also { it.start() }
private val stateMutationKey = TimeManager.time.intTimeMS().toString()
val statesMutationEval = MutableSharedFlow<String>()
var typedAnswer = ""
private var typedAnswer = ""

private val autoAdvance = AutoAdvance(this)
private val isHtmlTypeAnswerEnabled = Prefs.isHtmlTypeAnswerEnabled
Expand Down Expand Up @@ -185,6 +187,17 @@ class ReviewerViewModel :
while (!statesMutated) {
delay(50)
}

val typedAnswerResult = CompletableDeferred<String>()
if (typeAnswerFlow.value != null) {
onTypedAnswerResultFlow.emit(typedAnswerResult)
} else {
typedAnswerResult.complete("")
}
typedAnswer = withTimeoutOrNull(1000L) {
typedAnswerResult.await()
} ?: ""

updateNextTimes()
showAnswer()
loadAndPlayMedia(CardSide.ANSWER)
Expand Down Expand Up @@ -415,7 +428,7 @@ class ReviewerViewModel :
return
}
statesMutated = false
statesMutationEval.emit(
statesMutationEvalFlow.emit(
"anki.mutateNextCardStates('$stateMutationKey', async (states, customData, ctx) => { $js });",
)
}
Expand Down Expand Up @@ -560,7 +573,7 @@ class ReviewerViewModel :
val repl =
"""
<center>
<input type="text" id="typeans" oninput="ankidroid.onTypeAnswerInput(event);"
<input type="text" id="typeans" onkeydown="ankidroid.onTypeAnswerKeyDown(event);"
style="font-family: '${typeAnswer.font}'; font-size: ${typeAnswer.fontSize}px;">
</center>
""".trimIndent()
Expand Down