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

GT-2450 Add support for PageCollectionPages in CYOA tools #700

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
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 @@ -31,6 +31,7 @@ data class ParserConfig private constructor(
const val FEATURE_CONTENT_CARD = "content_card"
const val FEATURE_FLOW = "flow"
const val FEATURE_MULTISELECT = "multiselect"
const val FEATURE_PAGE_COLLECTION = "page-collection"
internal const val FEATURE_REQUIRED_VERSIONS = "required-versions"
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package org.cru.godtools.shared.tool.parser.model

import kotlin.experimental.ExperimentalObjCRefinement
import kotlin.js.ExperimentalJsExport
import kotlin.js.JsExport
import kotlin.js.JsName
import kotlin.native.HiddenFromObjC
import kotlin.reflect.KClass
import org.ccci.gto.support.androidx.annotation.RestrictTo
import org.ccci.gto.support.androidx.annotation.RestrictToScope
import org.cru.godtools.shared.tool.parser.model.page.Page

@JsExport

Check warning on line 13 in module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt

View check run for this annotation

Codecov / codecov/patch

module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt#L13

Added line #L13 was not covered by tests
@OptIn(ExperimentalJsExport::class, ExperimentalObjCRefinement::class)
interface HasPages : Base {
@JsName("_pages")
val pages: List<Page>

fun findPage(id: String?) = id?.let { pages.find { it.id == id } }

@HiddenFromObjC
@JsExport.Ignore
@RestrictTo(RestrictToScope.LIBRARY)
fun <T : Page> supportsPageType(type: KClass<T>): Boolean

// region Kotlin/JS interop
@HiddenFromObjC
@JsName("pages")
val jsPages get() = pages.toTypedArray()

Check warning on line 29 in module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt

View check run for this annotation

Codecov / codecov/patch

module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt#L29

Added line #L29 was not covered by tests
// endregion Kotlin/JS interop
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import kotlin.js.JsExport
import kotlin.js.JsName
import kotlin.native.HiddenFromObjC
import kotlin.reflect.KClass
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.coroutineScope
Expand All @@ -18,6 +19,7 @@
import org.cru.godtools.shared.common.model.isHttpUrl
import org.cru.godtools.shared.common.model.toUriOrNull
import org.cru.godtools.shared.tool.parser.ParserConfig
import org.cru.godtools.shared.tool.parser.ParserConfig.Companion.FEATURE_PAGE_COLLECTION
import org.cru.godtools.shared.tool.parser.internal.AndroidColorInt
import org.cru.godtools.shared.tool.parser.internal.DeprecationException
import org.cru.godtools.shared.tool.parser.internal.fluidlocale.toLocaleOrNull
Expand All @@ -27,15 +29,20 @@
import org.cru.godtools.shared.tool.parser.model.Multiselect.Companion.XML_MULTISELECT_OPTION_SELECTED_COLOR
import org.cru.godtools.shared.tool.parser.model.Styles.Companion.DEFAULT_TEXT_SCALE
import org.cru.godtools.shared.tool.parser.model.lesson.DEFAULT_LESSON_NAV_BAR_COLOR
import org.cru.godtools.shared.tool.parser.model.lesson.LessonPage
import org.cru.godtools.shared.tool.parser.model.lesson.XMLNS_LESSON
import org.cru.godtools.shared.tool.parser.model.page.CardCollectionPage
import org.cru.godtools.shared.tool.parser.model.page.ContentPage
import org.cru.godtools.shared.tool.parser.model.page.DEFAULT_CONTROL_COLOR
import org.cru.godtools.shared.tool.parser.model.page.Page
import org.cru.godtools.shared.tool.parser.model.page.PageCollectionPage
import org.cru.godtools.shared.tool.parser.model.page.XMLNS_PAGE
import org.cru.godtools.shared.tool.parser.model.page.XML_CONTROL_COLOR
import org.cru.godtools.shared.tool.parser.model.shareable.Shareable
import org.cru.godtools.shared.tool.parser.model.shareable.Shareable.Companion.parseShareableItems
import org.cru.godtools.shared.tool.parser.model.shareable.XMLNS_SHAREABLE
import org.cru.godtools.shared.tool.parser.model.tips.Tip
import org.cru.godtools.shared.tool.parser.model.tract.TractPage
import org.cru.godtools.shared.tool.parser.util.setOnce
import org.cru.godtools.shared.tool.parser.xml.XmlPullParser
import org.cru.godtools.shared.tool.parser.xml.parseChildren
Expand Down Expand Up @@ -67,7 +74,7 @@

@JsExport
@OptIn(ExperimentalJsExport::class, ExperimentalObjCRefinement::class)
class Manifest : BaseModel, Styles {
class Manifest : BaseModel, Styles, HasPages {
internal companion object {
@AndroidColorInt
internal val DEFAULT_PRIMARY_COLOR = color(59, 164, 219, 1.0)
Expand All @@ -94,8 +101,8 @@
// parse pages
if (config.parsePages) {
launch {
manifest.pages = manifest.pagesToParse
.map { (fileName, src) -> async { Page.parse(manifest, fileName, parseFile(src)) } }
manifest.pages = manifest.pageXmlFiles
.map { (name, src) -> async { Page.parse(manifest, name, parseFile(src), parseFile) } }
.awaitAll().filterNotNull()
}
} else {
Expand All @@ -105,8 +112,8 @@
// parse tips
if (config.parseTips) {
launch {
manifest.tips = manifest.tipsToParse
.map { (id, src) -> async { Tip(manifest, id, parseFile(src)) } }
manifest.tips = manifest.tipXmlFiles
.map { (id, src) -> async { Tip(manifest, id.orEmpty(), parseFile(src)) } }
.awaitAll()
.associateBy { it.id }
}
Expand Down Expand Up @@ -182,8 +189,7 @@

val aemImports: List<Uri>
val categories: List<Category>
@JsName("_pages")
var pages: List<Page> by setOnce()
override var pages: List<Page> by setOnce()
private set
@VisibleForTesting
internal val resources: Map<String?, Resource>
Expand All @@ -192,12 +198,12 @@
internal var tips: Map<String, Tip> by setOnce()
private set

private val pagesToParse: List<Pair<String?, String>>
private val tipsToParse: List<Pair<String, String>>
internal val pageXmlFiles: List<XmlFile>
private val tipXmlFiles: List<XmlFile>

val relatedFiles get() = buildSet {
addAll(pagesToParse.map { it.second })
addAll(tipsToParse.map { it.second })
addAll(pageXmlFiles.map { it.src })
addAll(tipXmlFiles.map { it.src })
addAll(resources.values.mapNotNull { it.localName })
}

Expand Down Expand Up @@ -249,8 +255,8 @@
categories = mutableListOf()
resources = mutableMapOf()
val shareables = mutableListOf<Shareable>()
pagesToParse = mutableListOf()
tipsToParse = mutableListOf()
pageXmlFiles = mutableListOf()
tipXmlFiles = mutableListOf()
parser.parseChildren {
@Suppress("ktlint:standard:blank-line-between-when-conditions")
when (parser.namespace) {
Expand All @@ -260,10 +266,10 @@
XML_PAGES -> {
val result = parser.parsePages()
aemImports += result.aemImports
pagesToParse += result.pages
pageXmlFiles += result.pages
}
XML_RESOURCES -> resources += parser.parseResources().associateBy { it.name }
XML_TIPS -> tipsToParse += parser.parseTips()
XML_TIPS -> tipXmlFiles += parser.parseTips()
}

XMLNS_SHAREABLE -> when (parser.name) {
Expand Down Expand Up @@ -298,7 +304,8 @@
resources: ((Manifest) -> List<Resource>)? = null,
shareables: ((Manifest) -> List<Shareable>)? = null,
tips: ((Manifest) -> List<Tip>)? = null,
pages: ((Manifest) -> List<Page>)? = null
pages: ((Manifest) -> List<Page>)? = null,
pageXmlFiles: List<XmlFile> = emptyList(),
) {
this.config = config

Expand Down Expand Up @@ -338,22 +345,34 @@
this.shareables = shareables?.invoke(this).orEmpty()
this.tips = tips?.invoke(this)?.associateBy { it.id }.orEmpty()

pagesToParse = emptyList()
tipsToParse = emptyList()
this.pageXmlFiles = pageXmlFiles
tipXmlFiles = emptyList()
}

override val manifest get() = this
val hasTips get() = tips.isNotEmpty() || (!config.parseTips && tipsToParse.isNotEmpty())
val hasTips get() = tips.isNotEmpty() || (!config.parseTips && tipXmlFiles.isNotEmpty())
internal fun getResource(name: String?) = name?.let { resources[name] }

@JsExport.Ignore
fun findCategory(category: String?) = categories.firstOrNull { it.id == category }
fun findPage(id: String?) = id?.let { pages.firstOrNull { it.id == id } }
@JsExport.Ignore
fun findShareable(id: String?) = id?.let { shareables.firstOrNull { it.id == id } }
@JsExport.Ignore
fun findTip(id: String?) = tips[id]

override fun <T : Page> supportsPageType(type: KClass<T>) = when (this.type) {
Type.ARTICLE -> false
Type.CYOA -> when (type) {
CardCollectionPage::class,
ContentPage::class -> true
PageCollectionPage::class -> config.supportsFeature(FEATURE_PAGE_COLLECTION)
else -> false
}
Type.LESSON -> type == LessonPage::class
Type.TRACT -> type == TractPage::class
Type.UNKNOWN -> false

Check warning on line 373 in module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt

View check run for this annotation

Codecov / codecov/patch

module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt#L373

Added line #L373 was not covered by tests
}

private fun XmlPullParser.parseCategories() = buildList {
require(XmlPullParser.START_TAG, XMLNS_MANIFEST, XML_CATEGORIES)
parseChildren {
Expand All @@ -367,7 +386,7 @@

private class PagesData {
val aemImports = mutableListOf<Uri>()
val pages = mutableListOf<Pair<String?, String>>()
val pages = mutableListOf<XmlFile>()
}

private fun XmlPullParser.parsePages() = PagesData().also { result ->
Expand All @@ -380,7 +399,7 @@
XML_PAGES_PAGE -> {
val src = getAttributeValue(XML_PAGES_PAGE_SRC) ?: return@parseChildren
val fileName = getAttributeValue(XML_PAGES_PAGE_FILENAME)
result.pages += fileName to src
result.pages += XmlFile(fileName, src)
}
}

Expand Down Expand Up @@ -411,7 +430,7 @@
XML_TIPS_TIP -> {
val id = getAttributeValue(XML_TIPS_TIP_ID) ?: return@parseChildren
val src = getAttributeValue(XML_TIPS_TIP_SRC) ?: return@parseChildren
add(id to src)
add(XmlFile(id, src))
}
}
}
Expand All @@ -422,10 +441,6 @@
@HiddenFromObjC
@JsName("dismissListeners")
val jsDismissListeners get() = dismissListeners.toTypedArray()

@HiddenFromObjC
@JsName("pages")
val jsPages get() = pages.toTypedArray()
// endregion Kotlin/JS interop

enum class Type {
Expand All @@ -448,6 +463,8 @@
}
}
}

data class XmlFile(internal val name: String?, internal val src: String)
}

@get:AndroidColorInt
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import org.cru.godtools.shared.tool.parser.model.AnalyticsEvent
import org.cru.godtools.shared.tool.parser.model.AnalyticsEvent.Companion.parseAnalyticsEvents
import org.cru.godtools.shared.tool.parser.model.Content
import org.cru.godtools.shared.tool.parser.model.Gravity
import org.cru.godtools.shared.tool.parser.model.HasPages
import org.cru.godtools.shared.tool.parser.model.ImageScaleType
import org.cru.godtools.shared.tool.parser.model.Manifest
import org.cru.godtools.shared.tool.parser.model.Parent
Expand All @@ -27,10 +28,10 @@ class LessonPage : Page, Parent {
override val content: List<Content>

internal constructor(
manifest: Manifest,
container: HasPages,
fileName: String?,
parser: XmlPullParser
) : super(manifest, fileName, parser) {
) : super(container, fileName, parser) {
parser.require(XmlPullParser.START_TAG, XMLNS_LESSON, XML_PAGE)

analyticsEvents = mutableListOf()
Expand Down Expand Up @@ -71,6 +72,4 @@ class LessonPage : Page, Parent {

content = emptyList()
}

override fun supports(type: Manifest.Type) = type == Manifest.Type.LESSON
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.cru.godtools.shared.tool.parser.model.AnalyticsEvent.Trigger
import org.cru.godtools.shared.tool.parser.model.BaseModel
import org.cru.godtools.shared.tool.parser.model.Content
import org.cru.godtools.shared.tool.parser.model.HasAnalyticsEvents
import org.cru.godtools.shared.tool.parser.model.HasPages
import org.cru.godtools.shared.tool.parser.model.Manifest
import org.cru.godtools.shared.tool.parser.model.Parent
import org.cru.godtools.shared.tool.parser.model.PlatformColor
Expand All @@ -32,10 +33,10 @@ class CardCollectionPage : Page {
val cards: List<Card>

internal constructor(
manifest: Manifest,
container: HasPages,
fileName: String?,
parser: XmlPullParser
) : super(manifest, fileName, parser) {
) : super(container, fileName, parser) {
parser.require(XmlPullParser.START_TAG, XMLNS_PAGE, XML_PAGE)
parser.requirePageType(TYPE_CARD_COLLECTION)

Expand Down Expand Up @@ -72,8 +73,6 @@ class CardCollectionPage : Page {
cards = emptyList()
}

override fun supports(type: Manifest.Type) = type == Manifest.Type.CYOA

class Card : BaseModel, Parent, HasAnalyticsEvents {
internal companion object {
internal const val XML_CARD = "card"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.ccci.gto.support.androidx.annotation.RestrictToScope
import org.cru.godtools.shared.tool.parser.model.AnalyticsEvent
import org.cru.godtools.shared.tool.parser.model.AnalyticsEvent.Companion.parseAnalyticsEvents
import org.cru.godtools.shared.tool.parser.model.Content
import org.cru.godtools.shared.tool.parser.model.Manifest
import org.cru.godtools.shared.tool.parser.model.HasPages
import org.cru.godtools.shared.tool.parser.model.Parent
import org.cru.godtools.shared.tool.parser.model.XMLNS_ANALYTICS
import org.cru.godtools.shared.tool.parser.model.parseContent
Expand All @@ -23,10 +23,10 @@ class ContentPage : Page, Parent {
override val content: List<Content>

internal constructor(
manifest: Manifest,
container: HasPages,
fileName: String?,
parser: XmlPullParser
) : super(manifest, fileName, parser) {
) : super(container, fileName, parser) {
parser.require(XmlPullParser.START_TAG, XMLNS_PAGE, XML_PAGE)
parser.requirePageType(TYPE_CONTENT)

Expand All @@ -47,13 +47,11 @@ class ContentPage : Page, Parent {

@RestrictTo(RestrictToScope.TESTS)
internal constructor(
manifest: Manifest,
container: HasPages,
id: String? = null,
parentPage: String? = null
) : super(manifest, id = id, parentPage = parentPage) {
) : super(container, id = id, parentPage = parentPage) {
analyticsEvents = emptyList()
content = emptyList()
}

override fun supports(type: Manifest.Type) = type == Manifest.Type.CYOA
}
Loading
Loading