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 @@ -55,8 +55,14 @@ class TemplatePreviewerPage : Fragment(R.layout.template_previewer_container) {
val tabLayout = view.findViewById<TabLayout>(R.id.tab_layout)

lifecycleScope.launch {
for (templateName in viewModel.getTemplateNames()) {
tabLayout.addTab(tabLayout.newTab().setText(templateName))
val cardsWithEmptyFronts = viewModel.cardsWithEmptyFronts?.await()
for ((index, templateName) in viewModel.getTemplateNames().withIndex()) {
val newTab = tabLayout.newTab().setText(templateName)
if (cardsWithEmptyFronts?.get(index) == true) {
val badge = newTab.getOrCreateBadge()
badge.horizontalOffset = -4
}
tabLayout.addTab(newTab)
}
tabLayout.selectTab(tabLayout.getTabAt(viewModel.getCurrentTabIndex()))
tabLayout.addOnTabSelectedListener(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import kotlinx.coroutines.Deferred
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.parcelize.Parcelize
import org.intellij.lang.annotations.Language
import org.jetbrains.annotations.VisibleForTesting

class TemplatePreviewerViewModel(
Expand All @@ -63,6 +64,11 @@ class TemplatePreviewerViewModel(
override var currentCard: Deferred<Card>
override val server = AnkiServer(this).also { it.start() }

/**
* Ordered list of cards with empty fronts
*/
internal val cardsWithEmptyFronts: Deferred<List<Boolean>>?

init {
note =
asyncIO {
Expand Down Expand Up @@ -105,9 +111,28 @@ class TemplatePreviewerViewModel(
val tr = CollectionManager.TR
clozeNumbers.await().map { tr.cardTemplatesCard(it) }
}
cardsWithEmptyFronts = null
} else {
clozeOrds = null
templateNames = CompletableDeferred(notetype.templatesNames)
cardsWithEmptyFronts =
asyncIO {
val note = note.await()
List(templateNames.await().size) { ord ->
val questionText =
withCol {
note
.ephemeralCard(
col = this,
ord = ord,
customNoteType = notetype,
fillEmpty = fillEmpty,
deckId = arguments.deckId,
).renderOutput(this)
}.questionText
EMPTY_FRONT_LINK in questionText
}
}
}
}

Expand Down Expand Up @@ -205,6 +230,9 @@ class TemplatePreviewerViewModel(
}

companion object {
@Language("HTML")
private const val EMPTY_FRONT_LINK = """<a href='https://docs.ankiweb.net/templates/errors.html#front-of-card-is-blank'>"""

fun factory(
arguments: TemplatePreviewerArguments,
cardMediaPlayer: CardMediaPlayer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,21 @@ class TemplatePreviewerViewModelTest : JvmTest() {
}
}

@Test
fun `empty front field detected correctly for tab badge`() =
runOptionalReversedTest(
fields =
mutableListOf(
"we have two normal fields",
"and purposefully leave the third blank",
"",
),
) {
onPageFinished(false)
assertThat(this.cardsWithEmptyFronts!!.await()[0], equalTo(false))
assertThat(this.cardsWithEmptyFronts!!.await()[1], equalTo(true))
}

private fun runClozeTest(
ord: Int = 0,
fields: MutableList<String>? = null,
Expand All @@ -73,4 +88,21 @@ class TemplatePreviewerViewModelTest : JvmTest() {
val viewModel = TemplatePreviewerViewModel(arguments, mock())
block(viewModel)
}

private fun runOptionalReversedTest(
ord: Int = 0,
fields: MutableList<String>? = null,
block: suspend TemplatePreviewerViewModel.() -> Unit,
) = runTest {
val notetype = col.notetypes.byName("Basic (optional reversed card)")!!
val arguments =
TemplatePreviewerArguments(
notetypeFile = NotetypeFile(tempDirectory.root, notetype),
fields = fields ?: mutableListOf("question text", "answer text", "y"),
tags = mutableListOf(),
ord = ord,
)
val viewModel = TemplatePreviewerViewModel(arguments, mock())
block(viewModel)
}
}