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

Feature/ios/xml #298

Draft
wants to merge 13 commits into
base: dev
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -1,78 +1,78 @@
package com.github.braillesystems.learnbraille.data.entities

import androidx.room.TypeConverter
import com.github.braillesystems.learnbraille.data.entities.BrailleDot.E
import com.github.braillesystems.learnbraille.data.entities.BrailleDot.F
import kotlinx.serialization.Serializable

/**
* State of one Braille dot.
*/
enum class BrailleDot {
E, // Empty
F; // Filled

companion object Factories {
fun valueOf(b: Boolean) = if (b) F else E
fun valueOf(c: Char) = valueOf(c.toString())
}
}

/**
* Combination on Braille dots for one symbol in 6-dots notation.
*/
@Serializable
data class BrailleDots(
val b1: BrailleDot = E, val b2: BrailleDot = E, val b3: BrailleDot = E,
val b4: BrailleDot = E, val b5: BrailleDot = E, val b6: BrailleDot = E
) {

constructor(dots: BooleanArray) : this(
dots.map(BrailleDot.Factories::valueOf)
)

constructor(dots: List<BrailleDot>) : this(
b1 = dots[0],
b2 = dots[1],
b3 = dots[2],
b4 = dots[3],
b5 = dots[4],
b6 = dots[5]
) {
require(dots.size == 6) {
"Only 6 dots braille notation supported"
}
}

constructor(string: String) : this(
string
.toCharArray()
.map(BrailleDot.Factories::valueOf)
)

override fun toString() = "$b1$b2$b3$b4$b5$b6"
}

val BrailleDots.list: List<BrailleDot>
get() = listOf(b1, b2, b3, b4, b5, b6)

val BrailleDots.spelling: String
get() = filled.joinToString(separator = ", ", transform = Int::toString)

val BrailleDots.filled: List<Int>
get() = list
.mapIndexedNotNull { index, brailleDot ->
if (brailleDot == F) index + 1
else null
}

operator fun BrailleDots.contains(i: Int) = i in filled

class BrailleDotsConverters {

@TypeConverter
fun to(brailleDots: BrailleDots) = brailleDots.toString()

@TypeConverter
fun from(data: String) = BrailleDots(data)
}
package com.github.braillesystems.learnbraille.data.entities
import androidx.room.TypeConverter
import com.github.braillesystems.learnbraille.data.entities.BrailleDot.E
import com.github.braillesystems.learnbraille.data.entities.BrailleDot.F
import kotlinx.serialization.Serializable
/**
* State of one Braille dot.
*/
enum class BrailleDot {
E, // Empty
F; // Filled
companion object Factories {
fun valueOf(b: Boolean) = if (b) F else E
fun valueOf(c: Char) = valueOf(c.toString())
}
}
/**
* Combination on Braille dots for one symbol in 6-dots notation.
*/
@Serializable
data class BrailleDots(
val b1: BrailleDot = E, val b2: BrailleDot = E, val b3: BrailleDot = E,
val b4: BrailleDot = E, val b5: BrailleDot = E, val b6: BrailleDot = E
) {
constructor(dots: BooleanArray) : this(
dots.map(BrailleDot.Factories::valueOf)
)
constructor(dots: List<BrailleDot>) : this(
b1 = dots[0],
b2 = dots[1],
b3 = dots[2],
b4 = dots[3],
b5 = dots[4],
b6 = dots[5]
) {
require(dots.size == 6) {
"Only 6 dots braille notation supported"
}
}
constructor(string: String) : this(
string
.toCharArray()
.map(BrailleDot.Factories::valueOf)
)
override fun toString() = "$b1$b2$b3$b4$b5$b6"
}
val BrailleDots.list: List<BrailleDot>
get() = listOf(b1, b2, b3, b4, b5, b6)
val BrailleDots.spelling: String
get() = filled.joinToString(separator = ", ", transform = Int::toString)
val BrailleDots.filled: List<Int>
get() = list
.mapIndexedNotNull { index, brailleDot ->
if (brailleDot == F) index + 1
else null
}
operator fun BrailleDots.contains(i: Int) = i in filled
class BrailleDotsConverters {
@TypeConverter
fun to(brailleDots: BrailleDots) = brailleDots.toString()
@TypeConverter
fun from(data: String) = BrailleDots(data)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class MaterialDataTypeConverters {
fun from(s: String): MaterialData = Json.parse(MaterialData.serializer(), s)
}

typealias SymbolType = String
typealias SymbolTypeName = String

@Serializable
sealed class OneBrailleSymbol : MaterialData() {
Expand All @@ -33,7 +33,7 @@ data class Symbol(
val char: Char,
override val brailleDots: BrailleDots,
@SerialName("symbol_type")
val type: SymbolType
val type: SymbolTypeName
) : OneBrailleSymbol()

@Serializable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ sealed class BaseShow : StepData() {
data class Show(
val material: Material
) : BaseShow() {

override val brailleDots: BrailleDots
get() = when (material.data) {
is OneBrailleSymbol -> material.data.brailleDots
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.github.braillesystems.learnbraille.data.entities

interface XmlAble {
val xmlTag: String
val xmlParams: Map<String, String>
val xmlBody: HtmlText
fun toXml(): HtmlText {
val paramsStringBuilder = StringBuilder()
for ((key, value) in xmlParams) {
val formattedValue = value.replace("\"", "'").replace("<br>", "")
paramsStringBuilder.append(" $key=\"$formattedValue\"")
}

val formattedBody = xmlBody.replace("\n +".toRegex(), "\n")
return "<$xmlTag$paramsStringBuilder>\n$formattedBody\n</$xmlTag>"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package com.github.braillesystems.learnbraille.data.entities

import com.github.braillesystems.learnbraille.data.dsl.LessonWithSteps
import com.github.braillesystems.learnbraille.data.dsl.lessons
import org.junit.Assert.assertEquals
import org.junit.Test

import com.github.braillesystems.learnbraille.data.entities.BrailleDot.F
import com.github.braillesystems.learnbraille.data.entities.BrailleDot.E
import com.github.braillesystems.learnbraille.res.golubinaIntroLessons
import com.github.braillesystems.learnbraille.res.SymbolType
import java.io.File
import java.lang.StringBuilder

internal val testLessons by lessons {
lesson(name = "first lesson") {
+FirstInfo("first title")
}
}

internal fun toXml(brailleDots: BrailleDots): HtmlText {
val dotsSymbols = brailleDots.toString().replace("F", "T").replace("E", "F")
var result = ""
dotsSymbols.dropLast(1).forEach { result += "$it, " }
result += dotsSymbols.takeLast(1)
return "<p>($result)</p>"
}

internal fun toXml(material: Material): HtmlText {
val sectionType = mapOf(
SymbolType.ru to "RussianSymbols",
SymbolType.digit to "Numbers",
SymbolType.math to "ArithmeticSymbols",
SymbolType.special to "PunctuationSymbols",
SymbolType.greek to "GreekSymbols(TODO)", // TODO
SymbolType.latin to "LatinSymbols(TODO)" // TODO
)

with(material.data) {
val result = when (this) {
is Symbol -> "${sectionType[this.type]}:${this.char}"
is MarkerSymbol -> "Signs:(TODO)" + this.brailleDots.spelling // TODO consult @braille-systems/ios-development
}
return "<p>$result</p>"
}
}

internal fun breaksToParagraphs(xmlBody: HtmlText): HtmlText {
val regex = "<br>".toRegex()
if (regex.find(xmlBody) == null) return xmlBody
val result = xmlBody.replace(regex, "</p>\n<p>")
return "<p>$result</p>"
}

internal fun toXml(stepData: StepData): HtmlText =
when (stepData) {
is BaseInfo -> object : XmlAble {
override val xmlTag: String = "text"
override val xmlParams: Map<String, String> = mapOf("type" to "info")
override val xmlBody: HtmlText = breaksToParagraphs(stepData.text)
}
is BaseInput -> object : XmlAble {
override val xmlTag: String = "practice"
override val xmlParams = mapOf(
"type" to "practice",
"title" to if (stepData is InputDots) stepData.text ?: "" else ""
)
override val xmlBody: HtmlText = when (stepData) {
is InputDots -> toXml(stepData.brailleDots)
is Input -> toXml(stepData.material)
else -> "toXml not implemented for this class"
}
}
is BaseShow -> object : XmlAble {
override val xmlTag: String = "reading"
override val xmlParams = mapOf(
"type" to "reading",
"title" to if (stepData is ShowDots) stepData.text ?: "" else ""
)
override val xmlBody: HtmlText = when (stepData) {
is ShowDots -> toXml(stepData.brailleDots)
is Show -> toXml(stepData.material)
else -> "toXml not implemented for this class"
}
}
else -> object : XmlAble {
override val xmlTag: String = stepData.toString()
override val xmlParams: Map<String, String> = mapOf()
override val xmlBody: HtmlText = "toXml not implemented for this class"
}
}.toXml()

internal fun toXml(lesson: LessonWithSteps): HtmlText {
return object : XmlAble {
override val xmlTag: String = "lesson"

override val xmlParams: Map<String, String> =
mapOf("name" to lesson.first.name)

override val xmlBody: HtmlText
get() = {
val stepBuilder = StringBuilder()
for (step in lesson.second.dropLast(1)) {
stepBuilder.append(toXml(step.first.data) + "\n")
}
stepBuilder.append(toXml(lesson.second.takeLast(1)[0].first.data))
stepBuilder.toString()
}()
}.toXml()
}

class ToXmlTest {
@Test
fun stepsToXml() {
val cases = mapOf<String, StepData>(
"""<text type="info">dummy text</text>""" to Info("dummy text"),
"""<text type="info">dummy last text</text>""" to LastInfo("dummy last text"),
"""<reading type="reading" title="look at these dots!"><p>(F, F, F, F, F, F)</p></reading>"""
to ShowDots("look at these dots!", BrailleDots()),
"""<practice type="practice" title="type in these dots!"><p>(F, F, T, F, F, T)</p></practice>"""
to InputDots("type in these dots!", BrailleDots(E, E, F, E, E, F))
)
for ((expectedXml, stepData) in cases) {
assertEquals(expectedXml, toXml(stepData).replace("\n", ""))
}
}

@Test
fun lessonToXml() {
assertEquals(
"""<lesson name="first lesson"><text type="info">first title</text></lesson>""",
toXml(testLessons.lessons[0]).replace("\n", "")
)
}

@Test
fun dumpGolubinaLessons() {
var xmlText = ""
for (lessons in golubinaIntroLessons.lessons) {
xmlText += (toXml(lessons) + "\n")
}

val xmlLinesList = xmlText.split("\n")
val outputPath = "course.xml"
File(outputPath).printWriter().use { out ->
out.println("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
out.println("<root>")
xmlLinesList.forEach { out.println(it) }
out.println("</root>")
}
print("course dumped to file: `$outputPath`")
}
}