Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GSoC'24] Chore: extension method to get cloze field name #16424

Merged
merged 2 commits into from
May 26, 2024
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
75 changes: 75 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/utils/CardTemplateJson.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2024 Ashish Yadav <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.ichi2.anki.utils

import com.ichi2.utils.deepClonedInto
import org.intellij.lang.annotations.Language
import org.json.JSONObject

class CardTemplateJson : JSONObject {
/**
* Creates a new empty model object
*/
constructor() : super()

/**
* Creates a copy from [JSONObject] and use it as a string
*
* This function will perform deepCopy on the passed object
*
* @see CardTemplateJson.from
*/
constructor(json: JSONObject) : super() {
json.deepClonedInto(this)
}

/**
* Creates a model object form json string
*/
constructor(@Language("json") json: String) : super(json)

val name: String
get() = getString("name")

val ord: Int
get() = getInt("ord")

val qfmt: String
get() = getString("qfmt")

val afmt: String
get() = getString("afmt")

val bqfmt: String
get() = getString("bqfmt")

val bafmt: String
get() = getString("bafmt")

val did: Long?
get() = if (isNull("did")) null else getLong("did")

val bfont: String
get() = getString("bfont")

val bsize: Int
get() = getInt("bsize")

val id: Long
get() = getLong("id")
}
19 changes: 19 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/utils/ext/NoteType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
package com.ichi2.anki.utils.ext

import anki.notetypes.StockNotetype.OriginalStockKind.ORIGINAL_STOCK_KIND_IMAGE_OCCLUSION_VALUE
import com.ichi2.anki.utils.CardTemplateJson
import com.ichi2.libanki.NotetypeJson
import com.ichi2.utils.jsonObjectIterable
import org.json.JSONException

/**
Expand All @@ -29,3 +31,20 @@ val NotetypeJson.isImageOcclusion: Boolean
} catch (e: JSONException) {
false
}

/**
* Regular expression pattern for extracting cloze text fields.
*/
private val clozeRegex = "\\{\\{(?:.*?:)?cloze:([^}]*)\\}\\}".toRegex()

val NotetypeJson.templates: List<CardTemplateJson>
get() = getJSONArray("tmpls").jsonObjectIterable().map { CardTemplateJson(it) }

fun NotetypeJson.getAllClozeTextFields(): List<String> {
if (!this.isCloze) {
throw IllegalStateException("getAllClozeTextFields called on non-cloze template")
}

val questionFormat = templates.single().qfmt
return clozeRegex.findAll(questionFormat).map { it.groups[1]!!.value }.toList()
}
2 changes: 1 addition & 1 deletion AnkiDroid/src/main/java/com/ichi2/libanki/NotetypeJson.kt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class NotetypeJson : JSONObject {
}

/**
* Creates a model object form json string
* Creates a model object from json string
*/
constructor(@Language("json") json: String) : super(json)

Expand Down
86 changes: 86 additions & 0 deletions AnkiDroid/src/test/java/com/ichi2/utils/NoteTypeTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2024 Ashish Yadav <[email protected]>
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.ichi2.utils

import com.ichi2.anki.utils.ext.getAllClozeTextFields
import com.ichi2.anki.utils.ext.templates
import com.ichi2.libanki.NotetypeJson
import junit.framework.TestCase.assertEquals
import kotlin.test.Test

// link to a method in `NoteType.kt` for navigation as it contains no classes
/** Test of [NoteType][templates] */
class NoteTypeTest {

private val noteType = """
{
"type":1,
"tmpls":[
{
"name":"Cloze",
"ord":0,
"qfmt":"{{type:cloze:Text}} {{type:cloze:Text2}} {{cloze:Text3}} {{Added field}}",
"afmt":"{{cloze:Text}}<br>\n{{Back Extra}}",
"bqfmt":"",
"bafmt":"",
"did":null,
"bfont":"",
"bsize":0,
"id":1716321740
}
]
}
"""

@Test
fun testQfmtField() {
val notetypeJson = NotetypeJson(noteType)

val expectedQfmt = "{{type:cloze:Text}} {{type:cloze:Text2}} {{cloze:Text3}} {{Added field}}"
assertEquals(expectedQfmt, notetypeJson.templates[0].qfmt)
}

@Test
fun testGetAllClozeTexts() {
val notetypeJson = NotetypeJson(noteType)

val expectedClozeTexts = listOf("Text", "Text2", "Text3")
assertEquals(expectedClozeTexts, notetypeJson.getAllClozeTextFields())
}

@Test
fun testNameField() {
val notetypeJson = NotetypeJson(noteType)
val expectedName = "Cloze"
assertEquals(expectedName, notetypeJson.templates[0].name)
}

@Test
fun testOrdField() {
val notetypeJson = NotetypeJson(noteType)
val expectedOrd = 0
assertEquals(expectedOrd, notetypeJson.templates[0].ord)
}

@Test
fun testAfmtField() {
val notetypeJson = NotetypeJson(noteType)
val expectedAfmt = "{{cloze:Text}}<br>\n{{Back Extra}}"
assertEquals(expectedAfmt, notetypeJson.templates[0].afmt)
}
}