From bcf9f5ef2ab36c1eaa212ce6195f5d9515bd3960 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Tue, 15 Oct 2024 14:17:56 -0600 Subject: [PATCH 01/13] create a HasPages interface --- .../shared/tool/parser/model/HasPages.kt | 23 +++++++++++++++++++ .../shared/tool/parser/model/Manifest.kt | 10 ++------ .../tool/parser/model/lesson/LessonPage.kt | 5 ++-- .../parser/model/page/CardCollectionPage.kt | 5 ++-- .../tool/parser/model/page/ContentPage.kt | 9 ++++---- .../shared/tool/parser/model/page/Page.kt | 19 +++++++-------- .../tool/parser/model/tract/TractPage.kt | 5 ++-- .../analytics/ToolAnalyticsScreenNamesTest.kt | 2 +- .../shared/tool/parser/model/page/PageTest.kt | 2 +- 9 files changed, 51 insertions(+), 29 deletions(-) create mode 100644 module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt new file mode 100644 index 000000000..92aab5091 --- /dev/null +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt @@ -0,0 +1,23 @@ +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 org.cru.godtools.shared.tool.parser.model.page.Page + +@JsExport +@OptIn(ExperimentalJsExport::class, ExperimentalObjCRefinement::class) +interface HasPages : Base { + @JsName("_pages") + val pages: List + + fun findPage(id: String?) = id?.let { pages.find { it.id == id } } + + // region Kotlin/JS interop + @HiddenFromObjC + @JsName("pages") + val jsPages get() = pages.toTypedArray() + // endregion Kotlin/JS interop +} diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt index ae2c282c4..56c7881e4 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt @@ -67,7 +67,7 @@ private const val XML_TIPS_TIP_SRC = "src" @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) @@ -182,8 +182,7 @@ class Manifest : BaseModel, Styles { val aemImports: List val categories: List - @JsName("_pages") - var pages: List by setOnce() + override var pages: List by setOnce() private set @VisibleForTesting internal val resources: Map @@ -348,7 +347,6 @@ class Manifest : BaseModel, Styles { @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 @@ -422,10 +420,6 @@ class Manifest : BaseModel, Styles { @HiddenFromObjC @JsName("dismissListeners") val jsDismissListeners get() = dismissListeners.toTypedArray() - - @HiddenFromObjC - @JsName("pages") - val jsPages get() = pages.toTypedArray() // endregion Kotlin/JS interop enum class Type { diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/lesson/LessonPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/lesson/LessonPage.kt index 5dc77675c..84441a253 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/lesson/LessonPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/lesson/LessonPage.kt @@ -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 @@ -27,10 +28,10 @@ class LessonPage : Page, Parent { override val content: List 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() diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/CardCollectionPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/CardCollectionPage.kt index 293ead54a..d34930d6b 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/CardCollectionPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/CardCollectionPage.kt @@ -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 @@ -32,10 +33,10 @@ class CardCollectionPage : Page { val cards: List 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) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/ContentPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/ContentPage.kt index 7b77eb7d4..42025b8f0 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/ContentPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/ContentPage.kt @@ -5,6 +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.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.XMLNS_ANALYTICS @@ -23,10 +24,10 @@ class ContentPage : Page, Parent { override val content: List 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) @@ -47,10 +48,10 @@ 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() } diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index 0642d42fd..ae829ccc9 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -18,6 +18,7 @@ import org.cru.godtools.shared.tool.parser.model.EventId import org.cru.godtools.shared.tool.parser.model.Gravity import org.cru.godtools.shared.tool.parser.model.Gravity.Companion.toGravityOrNull 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.ImageScaleType import org.cru.godtools.shared.tool.parser.model.ImageScaleType.Companion.toImageScaleTypeOrNull import org.cru.godtools.shared.tool.parser.model.Manifest @@ -78,16 +79,16 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { @VisibleForTesting internal val DEFAULT_BACKGROUND_IMAGE_SCALE_TYPE = ImageScaleType.FILL_X - fun parse(manifest: Manifest, fileName: String?, parser: XmlPullParser): Page? { + internal fun parse(container: HasPages, fileName: String?, parser: XmlPullParser): Page? { parser.require(XmlPullParser.START_TAG, null, XML_PAGE) @Suppress("ktlint:standard:blank-line-between-when-conditions") return when (parser.namespace) { - XMLNS_LESSON -> LessonPage(manifest, fileName, parser) - XMLNS_TRACT -> TractPage(manifest, fileName, parser) + XMLNS_LESSON -> LessonPage(container, fileName, parser) + XMLNS_TRACT -> TractPage(container, fileName, parser) XMLNS_PAGE -> when (val type = parser.getAttributeValue(XMLNS_XSI, XML_TYPE)) { - TYPE_CARD_COLLECTION -> CardCollectionPage(manifest, fileName, parser) - TYPE_CONTENT -> ContentPage(manifest, fileName, parser) + TYPE_CARD_COLLECTION -> CardCollectionPage(container, fileName, parser) + TYPE_CONTENT -> ContentPage(container, fileName, parser) else -> { val message = "Unrecognized page type: <${parser.namespace}:${parser.name} type=$type>" Logger.e(message, UnsupportedOperationException(message), "Page") @@ -99,7 +100,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { Logger.e(message, UnsupportedOperationException(message), "Page") null } - }?.takeIf { it.supports(manifest.type) } + }?.takeIf { it.supports(container.manifest.type) } } internal fun XmlPullParser.requirePageType(type: String) { @@ -170,7 +171,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { private val _textScale: Double override val textScale get() = _textScale * stylesParent.textScale - internal constructor(manifest: Manifest, fileName: String?, parser: XmlPullParser) : super(manifest) { + internal constructor(container: HasPages, fileName: String?, parser: XmlPullParser) : super(container) { parser.require(XmlPullParser.START_TAG, null, XML_PAGE) _id = parser.getAttributeValue(XML_ID) @@ -208,7 +209,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { @RestrictTo(RestrictToScope.SUBCLASSES, RestrictToScope.TESTS) internal constructor( - manifest: Manifest = Manifest(), + container: HasPages = Manifest(), id: String? = null, fileName: String? = null, parentPage: String? = null, @@ -223,7 +224,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { multiselectOptionSelectedColor: PlatformColor? = null, textColor: PlatformColor? = null, textScale: Double = DEFAULT_TEXT_SCALE - ) : super(manifest) { + ) : super(container) { _id = id this.fileName = fileName _parentPage = parentPage diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPage.kt index e2caf6c51..e3dde9cfe 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPage.kt @@ -19,6 +19,7 @@ import org.cru.godtools.shared.tool.parser.model.EventId import org.cru.godtools.shared.tool.parser.model.Gravity import org.cru.godtools.shared.tool.parser.model.Gravity.Companion.toGravityOrNull 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.ImageScaleType import org.cru.godtools.shared.tool.parser.model.ImageScaleType.Companion.toImageScaleTypeOrNull import org.cru.godtools.shared.tool.parser.model.Manifest @@ -66,10 +67,10 @@ class TractPage : Page { val callToAction: CallToAction internal constructor( - manifest: Manifest, + container: HasPages, fileName: String?, parser: XmlPullParser - ) : super(manifest, fileName, parser) { + ) : super(container, fileName, parser) { parser.require(XmlPullParser.START_TAG, XMLNS_TRACT, XML_PAGE) _cardTextColor = parser.getAttributeValue(XML_CARD_TEXT_COLOR)?.toColorOrNull() diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/analytics/ToolAnalyticsScreenNamesTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/analytics/ToolAnalyticsScreenNamesTest.kt index d97a2f53c..253912d9f 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/analytics/ToolAnalyticsScreenNamesTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/analytics/ToolAnalyticsScreenNamesTest.kt @@ -14,7 +14,7 @@ class ToolAnalyticsScreenNamesTest { @Test fun testForCyoaPage() { val page = ContentPage( - manifest = Manifest(code = "cyoa"), + container = Manifest(code = "cyoa"), id = "page" ) diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt index c5a4ac497..44c524be1 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt @@ -153,7 +153,7 @@ class PageTest : UsesResources("model/page") { multiselectOptionSelectedColor: PlatformColor? = null, override val analyticsEvents: List = emptyList(), ) : Page( - manifest = manifest, + container = manifest, multiselectOptionBackgroundColor = multiselectOptionBackgroundColor, multiselectOptionSelectedColor = multiselectOptionSelectedColor, ) { From 487cd50d5732bca4a5214e393243e28f02d1de0c Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Thu, 17 Oct 2024 13:01:14 -0600 Subject: [PATCH 02/13] add a PAGE_COLLECTION feature for the parser config --- .../kotlin/org/cru/godtools/shared/tool/parser/ParserConfig.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/ParserConfig.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/ParserConfig.kt index 554383fd0..ec374a809 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/ParserConfig.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/ParserConfig.kt @@ -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" } From ba80cf83c6a0523da95d144b65660cbfda367bca Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Thu, 17 Oct 2024 13:18:24 -0600 Subject: [PATCH 03/13] add initial PageCollectionPage parsing support --- .../shared/tool/parser/model/page/Page.kt | 2 + .../parser/model/page/PageCollectionPage.kt | 64 +++++++++++++++++++ .../model/page/PageCollectionPageTest.kt | 44 +++++++++++++ .../model/page/page_page-collection.xml | 30 +++++++++ 4 files changed, 140 insertions(+) create mode 100644 module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt create mode 100644 module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPageTest.kt create mode 100644 module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_page-collection.xml diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index ae829ccc9..891c244bd 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -48,6 +48,7 @@ import org.cru.godtools.shared.tool.parser.model.page.ContentPage.Companion.TYPE import org.cru.godtools.shared.tool.parser.model.page.Page.Companion.DEFAULT_BACKGROUND_COLOR import org.cru.godtools.shared.tool.parser.model.page.Page.Companion.DEFAULT_BACKGROUND_IMAGE_GRAVITY import org.cru.godtools.shared.tool.parser.model.page.Page.Companion.DEFAULT_BACKGROUND_IMAGE_SCALE_TYPE +import org.cru.godtools.shared.tool.parser.model.page.PageCollectionPage.Companion.TYPE_PAGE_COLLECTION import org.cru.godtools.shared.tool.parser.model.primaryColor import org.cru.godtools.shared.tool.parser.model.primaryTextColor import org.cru.godtools.shared.tool.parser.model.stylesParent @@ -89,6 +90,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { XMLNS_PAGE -> when (val type = parser.getAttributeValue(XMLNS_XSI, XML_TYPE)) { TYPE_CARD_COLLECTION -> CardCollectionPage(container, fileName, parser) TYPE_CONTENT -> ContentPage(container, fileName, parser) + TYPE_PAGE_COLLECTION -> PageCollectionPage(container, fileName, parser) else -> { val message = "Unrecognized page type: <${parser.namespace}:${parser.name} type=$type>" Logger.e(message, UnsupportedOperationException(message), "Page") diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt new file mode 100644 index 000000000..a4587e0b9 --- /dev/null +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt @@ -0,0 +1,64 @@ +package org.cru.godtools.shared.tool.parser.model.page + +import org.cru.godtools.shared.tool.parser.ParserConfig.Companion.FEATURE_PAGE_COLLECTION +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.HasPages +import org.cru.godtools.shared.tool.parser.model.Manifest +import org.cru.godtools.shared.tool.parser.model.XMLNS_ANALYTICS +import org.cru.godtools.shared.tool.parser.xml.XmlPullParser +import org.cru.godtools.shared.tool.parser.xml.parseChildren + +class PageCollectionPage : Page, HasPages { + companion object { + internal const val TYPE_PAGE_COLLECTION = "page-collection" + + private const val XML_PAGES = "pages" + } + + override val analyticsEvents: List + override val pages: List + + internal constructor( + container: HasPages, + fileName: String?, + parser: XmlPullParser + ) : super(container, fileName, parser) { + parser.require(XmlPullParser.START_TAG, XMLNS_PAGE, XML_PAGE) + parser.requirePageType(TYPE_PAGE_COLLECTION) + + analyticsEvents = mutableListOf() + pages = mutableListOf() + parser.parseChildren { + when (parser.namespace) { + XMLNS_ANALYTICS -> when (parser.name) { + AnalyticsEvent.XML_EVENTS -> analyticsEvents += parser.parseAnalyticsEvents(this) + } + + XMLNS_PAGE -> when (parser.name) { + XML_PAGES -> pages += parser.parsePages() + } + } + } + } + + private fun XmlPullParser.parsePages() = buildList { + require(XmlPullParser.START_TAG, XMLNS_PAGE, XML_PAGES) + + // process any child elements + parseChildren { + when (namespace) { + XMLNS_PAGE -> when (name) { + XML_PAGE -> { + parse(this@PageCollectionPage, null, this@parsePages) + ?.takeIf { it is ContentPage } + ?.let { add(it) } + } + } + } + } + } + + override fun supports(type: Manifest.Type) = + type == Manifest.Type.CYOA && manifest.config.supportsFeature(FEATURE_PAGE_COLLECTION) +} diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPageTest.kt new file mode 100644 index 000000000..a47fe1c53 --- /dev/null +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPageTest.kt @@ -0,0 +1,44 @@ +package org.cru.godtools.shared.tool.parser.model.page + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFailsWith +import kotlin.test.assertIs +import kotlin.test.assertNotNull +import kotlinx.coroutines.test.runTest +import org.ccci.gto.support.androidx.test.junit.runners.AndroidJUnit4 +import org.ccci.gto.support.androidx.test.junit.runners.RunOnAndroidWith +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.UsesResources +import org.cru.godtools.shared.tool.parser.model.Manifest +import org.cru.godtools.shared.tool.parser.xml.XmlPullParserException + +@RunOnAndroidWith(AndroidJUnit4::class) +class PageCollectionPageTest : UsesResources("model/page") { + private val manifest = Manifest( + config = ParserConfig().withSupportedFeatures(FEATURE_PAGE_COLLECTION), + type = Manifest.Type.CYOA, + ) + + // region Parse XML + @Test + fun testParsePageCollectionPage() = runTest { + assertNotNull(PageCollectionPage(manifest, null, getTestXmlParser("page_page-collection.xml"))) { + assertEquals(1, it.analyticsEvents.size) + assertEquals(1, it.pages.size) + assertNotNull(it.pages[0]) { page -> + assertIs(page) + assertEquals("content_page", page.id) + } + } + } + + @Test + fun testParsePageCollectionPageInvalidType() = runTest { + assertFailsWith(XmlPullParserException::class) { + PageCollectionPage(manifest, null, getTestXmlParser("page_invalid_type.xml")) + } + } + // endregion Parse XML +} diff --git a/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_page-collection.xml b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_page-collection.xml new file mode 100644 index 000000000..5231c569a --- /dev/null +++ b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_page-collection.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + Text + + + + + + + + + + + + + From ebf0943c82aa34ae32811f8b3f6231df7a4a8b7e Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Fri, 18 Oct 2024 15:00:21 -0600 Subject: [PATCH 04/13] add a HasPages.supportsPageType() method to allow a container to specify what types of pages it supports --- .../shared/tool/parser/model/HasPages.kt | 8 +++ .../shared/tool/parser/model/Manifest.kt | 20 ++++++++ .../tool/parser/model/lesson/LessonPage.kt | 2 - .../parser/model/page/CardCollectionPage.kt | 2 - .../tool/parser/model/page/ContentPage.kt | 3 -- .../shared/tool/parser/model/page/Page.kt | 4 +- .../parser/model/page/PageCollectionPage.kt | 8 ++- .../tool/parser/model/tract/TractPage.kt | 2 - .../shared/tool/parser/model/ManifestTest.kt | 51 +++++++++++++++++++ .../shared/tool/parser/model/page/PageTest.kt | 4 +- 10 files changed, 84 insertions(+), 20 deletions(-) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt index 92aab5091..e6539ae04 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/HasPages.kt @@ -5,6 +5,9 @@ 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 @@ -15,6 +18,11 @@ interface HasPages : Base { fun findPage(id: String?) = id?.let { pages.find { it.id == id } } + @HiddenFromObjC + @JsExport.Ignore + @RestrictTo(RestrictToScope.LIBRARY) + fun supportsPageType(type: KClass): Boolean + // region Kotlin/JS interop @HiddenFromObjC @JsName("pages") diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt index 56c7881e4..ab949cb8a 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt @@ -6,6 +6,7 @@ import kotlin.js.ExperimentalJsExport 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 @@ -18,6 +19,7 @@ import org.cru.godtools.shared.common.model.Uri 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 @@ -27,15 +29,20 @@ import org.cru.godtools.shared.tool.parser.model.Multiselect.Companion.XML_MULTI 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 @@ -352,6 +359,19 @@ class Manifest : BaseModel, Styles, HasPages { @JsExport.Ignore fun findTip(id: String?) = tips[id] + override fun supportsPageType(type: KClass) = 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 + } + private fun XmlPullParser.parseCategories() = buildList { require(XmlPullParser.START_TAG, XMLNS_MANIFEST, XML_CATEGORIES) parseChildren { diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/lesson/LessonPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/lesson/LessonPage.kt index 84441a253..9431b0844 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/lesson/LessonPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/lesson/LessonPage.kt @@ -72,6 +72,4 @@ class LessonPage : Page, Parent { content = emptyList() } - - override fun supports(type: Manifest.Type) = type == Manifest.Type.LESSON } diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/CardCollectionPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/CardCollectionPage.kt index d34930d6b..14dc5bc64 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/CardCollectionPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/CardCollectionPage.kt @@ -73,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" diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/ContentPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/ContentPage.kt index 42025b8f0..6a1898b6d 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/ContentPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/ContentPage.kt @@ -6,7 +6,6 @@ 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.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.XMLNS_ANALYTICS import org.cru.godtools.shared.tool.parser.model.parseContent @@ -55,6 +54,4 @@ class ContentPage : Page, Parent { analyticsEvents = emptyList() content = emptyList() } - - override fun supports(type: Manifest.Type) = type == Manifest.Type.CYOA } diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index 891c244bd..751bf079c 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -102,7 +102,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { Logger.e(message, UnsupportedOperationException(message), "Page") null } - }?.takeIf { it.supports(container.manifest.type) } + }?.takeIf { container.supportsPageType(it::class) } } internal fun XmlPullParser.requirePageType(type: String) { @@ -255,8 +255,6 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { _textScale = textScale } - internal abstract fun supports(type: Manifest.Type): Boolean - // region HasAnalyticsEvents @VisibleForTesting internal abstract val analyticsEvents: List diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt index a4587e0b9..73795f5bc 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt @@ -1,10 +1,9 @@ package org.cru.godtools.shared.tool.parser.model.page -import org.cru.godtools.shared.tool.parser.ParserConfig.Companion.FEATURE_PAGE_COLLECTION +import kotlin.reflect.KClass 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.HasPages -import org.cru.godtools.shared.tool.parser.model.Manifest import org.cru.godtools.shared.tool.parser.model.XMLNS_ANALYTICS import org.cru.godtools.shared.tool.parser.xml.XmlPullParser import org.cru.godtools.shared.tool.parser.xml.parseChildren @@ -51,7 +50,7 @@ class PageCollectionPage : Page, HasPages { XMLNS_PAGE -> when (name) { XML_PAGE -> { parse(this@PageCollectionPage, null, this@parsePages) - ?.takeIf { it is ContentPage } + ?.takeIf { supportsPageType(it::class) } ?.let { add(it) } } } @@ -59,6 +58,5 @@ class PageCollectionPage : Page, HasPages { } } - override fun supports(type: Manifest.Type) = - type == Manifest.Type.CYOA && manifest.config.supportsFeature(FEATURE_PAGE_COLLECTION) + override fun supportsPageType(type: KClass) = type == ContentPage::class } diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPage.kt index e3dde9cfe..b32c79c7f 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPage.kt @@ -134,8 +134,6 @@ class TractPage : Page { this.callToAction = callToAction?.invoke(this) ?: CallToAction(this) } - override fun supports(type: Manifest.Type) = type == Manifest.Type.TRACT - fun findModal(id: String?) = modals.firstOrNull { it.id.equals(id, ignoreCase = true) } // region Cards diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/ManifestTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/ManifestTest.kt index 3c803586a..cdd048ac8 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/ManifestTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/ManifestTest.kt @@ -13,10 +13,15 @@ import org.ccci.gto.support.androidx.test.junit.runners.AndroidJUnit4 import org.ccci.gto.support.androidx.test.junit.runners.RunOnAndroidWith import org.ccci.gto.support.fluidsonic.locale.toCommon 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.UsesResources 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.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.PageCollectionPage import org.cru.godtools.shared.tool.parser.model.shareable.ShareableImage import org.cru.godtools.shared.tool.parser.model.tract.TractPage @@ -201,6 +206,7 @@ class ManifestTest : UsesResources() { Manifest.parse(name, config) { getTestXmlParser(it) } // endregion parse Manifest + // region HasPages @Test fun testManifestFindPage() { val manifest = Manifest(code = "tool", pages = { manifest -> List(10) { TractPage(manifest) } }) @@ -210,6 +216,51 @@ class ManifestTest : UsesResources() { } } + // region HasPages.supportsPageType() + @Test + fun testManifestSupportsPageType_Article() { + val manifest = Manifest(type = Manifest.Type.ARTICLE) + assertFalse(manifest.supportsPageType(ContentPage::class)) + assertFalse(manifest.supportsPageType(LessonPage::class)) + assertFalse(manifest.supportsPageType(TractPage::class)) + } + + @Test + fun testManifestSupportsPageType_Cyoa() { + val manifest = Manifest( + config = ParserConfig().withSupportedFeatures(FEATURE_PAGE_COLLECTION), + type = Manifest.Type.CYOA + ) + assertTrue(manifest.supportsPageType(ContentPage::class)) + assertTrue(manifest.supportsPageType(CardCollectionPage::class)) + assertTrue(manifest.supportsPageType(PageCollectionPage::class)) + assertFalse(manifest.supportsPageType(LessonPage::class)) + assertFalse(manifest.supportsPageType(TractPage::class)) + + assertFalse( + Manifest(type = Manifest.Type.CYOA).supportsPageType(PageCollectionPage::class), + "PageCollectionPages are only supported when the feature is enabled", + ) + } + + @Test + fun testManifestSupportsPageType_Lesson() { + val manifest = Manifest(type = Manifest.Type.LESSON) + assertTrue(manifest.supportsPageType(LessonPage::class)) + assertFalse(manifest.supportsPageType(ContentPage::class)) + assertFalse(manifest.supportsPageType(TractPage::class)) + } + + @Test + fun testManifestSupportsPageType_Tract() { + val manifest = Manifest(type = Manifest.Type.TRACT) + assertTrue(manifest.supportsPageType(TractPage::class)) + assertFalse(manifest.supportsPageType(ContentPage::class)) + assertFalse(manifest.supportsPageType(LessonPage::class)) + } + // endregion Manifest.supportsPageType() + // endregion HasPages + @Test fun testManifestFindShareable() { val manifest = Manifest(code = "tool", shareables = { List(5) { ShareableImage(id = "shareable$it") } }) diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt index 44c524be1..f5a505bd0 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt @@ -156,7 +156,5 @@ class PageTest : UsesResources("model/page") { container = manifest, multiselectOptionBackgroundColor = multiselectOptionBackgroundColor, multiselectOptionSelectedColor = multiselectOptionSelectedColor, - ) { - override fun supports(type: Manifest.Type) = true - } + ) } From 4c82aa387df9a5ddb39436c081c566bf20eaf1d1 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Fri, 18 Oct 2024 16:54:39 -0600 Subject: [PATCH 05/13] introduce an XmlFile data class to represent the xml files bundled with a manifest --- .../shared/tool/parser/model/Manifest.kt | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt index ab949cb8a..8771ca415 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt @@ -101,8 +101,8 @@ class Manifest : BaseModel, Styles, HasPages { // 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)) } } .awaitAll().filterNotNull() } } else { @@ -112,8 +112,8 @@ class Manifest : BaseModel, Styles, HasPages { // 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 } } @@ -198,12 +198,12 @@ class Manifest : BaseModel, Styles, HasPages { internal var tips: Map by setOnce() private set - private val pagesToParse: List> - private val tipsToParse: List> + private val pageXmlFiles: List + private val tipXmlFiles: List 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 }) } @@ -255,8 +255,8 @@ class Manifest : BaseModel, Styles, HasPages { categories = mutableListOf() resources = mutableMapOf() val shareables = mutableListOf() - pagesToParse = mutableListOf() - tipsToParse = mutableListOf() + pageXmlFiles = mutableListOf() + tipXmlFiles = mutableListOf() parser.parseChildren { @Suppress("ktlint:standard:blank-line-between-when-conditions") when (parser.namespace) { @@ -266,10 +266,10 @@ class Manifest : BaseModel, Styles, HasPages { 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) { @@ -344,12 +344,12 @@ class Manifest : BaseModel, Styles, HasPages { this.shareables = shareables?.invoke(this).orEmpty() this.tips = tips?.invoke(this)?.associateBy { it.id }.orEmpty() - pagesToParse = emptyList() - tipsToParse = emptyList() + pageXmlFiles = emptyList() + 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 @@ -385,7 +385,7 @@ class Manifest : BaseModel, Styles, HasPages { private class PagesData { val aemImports = mutableListOf() - val pages = mutableListOf>() + val pages = mutableListOf() } private fun XmlPullParser.parsePages() = PagesData().also { result -> @@ -398,7 +398,7 @@ class Manifest : BaseModel, Styles, HasPages { 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) } } @@ -429,7 +429,7 @@ class Manifest : BaseModel, Styles, HasPages { 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)) } } } @@ -462,6 +462,8 @@ class Manifest : BaseModel, Styles, HasPages { } } } + + data class XmlFile(internal val name: String?, internal val src: String) } @get:AndroidColorInt From dcd41b6d80c585da00b9a43f05a0965a5fcc618f Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 21 Oct 2024 10:49:11 -0600 Subject: [PATCH 06/13] support parsing imported pages for a PageCollection --- .../shared/tool/parser/model/Manifest.kt | 9 ++-- .../shared/tool/parser/model/page/Page.kt | 18 ++++++- .../parser/model/page/PageCollectionPage.kt | 49 ++++++++++++++++--- .../tool/parser/internal/UsesResources.kt | 3 ++ .../model/page/PageCollectionPageTest.kt | 22 ++++++++- .../shared/tool/parser/model/page/PageTest.kt | 31 ++++++++++++ .../tool/parser/model/page/page_content.xml | 2 +- .../page/page_page-collection_imports.xml | 26 ++++++++++ 8 files changed, 146 insertions(+), 14 deletions(-) create mode 100644 module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_page-collection_imports.xml diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt index 8771ca415..e1acbf815 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/Manifest.kt @@ -102,7 +102,7 @@ class Manifest : BaseModel, Styles, HasPages { if (config.parsePages) { launch { manifest.pages = manifest.pageXmlFiles - .map { (name, src) -> async { Page.parse(manifest, name, parseFile(src)) } } + .map { (name, src) -> async { Page.parse(manifest, name, parseFile(src), parseFile) } } .awaitAll().filterNotNull() } } else { @@ -198,7 +198,7 @@ class Manifest : BaseModel, Styles, HasPages { internal var tips: Map by setOnce() private set - private val pageXmlFiles: List + internal val pageXmlFiles: List private val tipXmlFiles: List val relatedFiles get() = buildSet { @@ -304,7 +304,8 @@ class Manifest : BaseModel, Styles, HasPages { resources: ((Manifest) -> List)? = null, shareables: ((Manifest) -> List)? = null, tips: ((Manifest) -> List)? = null, - pages: ((Manifest) -> List)? = null + pages: ((Manifest) -> List)? = null, + pageXmlFiles: List = emptyList(), ) { this.config = config @@ -344,7 +345,7 @@ class Manifest : BaseModel, Styles, HasPages { this.shareables = shareables?.invoke(this).orEmpty() this.tips = tips?.invoke(this)?.associateBy { it.id }.orEmpty() - pageXmlFiles = emptyList() + this.pageXmlFiles = pageXmlFiles tipXmlFiles = emptyList() } diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index 751bf079c..8478bbfae 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -80,6 +80,23 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { @VisibleForTesting internal val DEFAULT_BACKGROUND_IMAGE_SCALE_TYPE = ImageScaleType.FILL_X + internal suspend fun parse( + container: HasPages, + fileName: String?, + parser: XmlPullParser, + parseFile: suspend (String) -> XmlPullParser, + ): Page? { + parser.require(XmlPullParser.START_TAG, null, XML_PAGE) + + return when (parser.namespace to parser.getAttributeValue(XMLNS_XSI, XML_TYPE)) { + XMLNS_PAGE to TYPE_PAGE_COLLECTION -> { + if (!container.supportsPageType(PageCollectionPage::class)) return null + PageCollectionPage.parse(container, fileName, parser, parseFile) + } + else -> parse(container, fileName, parser) + }?.takeIf { container.supportsPageType(it::class) } + } + internal fun parse(container: HasPages, fileName: String?, parser: XmlPullParser): Page? { parser.require(XmlPullParser.START_TAG, null, XML_PAGE) @@ -90,7 +107,6 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { XMLNS_PAGE -> when (val type = parser.getAttributeValue(XMLNS_XSI, XML_TYPE)) { TYPE_CARD_COLLECTION -> CardCollectionPage(container, fileName, parser) TYPE_CONTENT -> ContentPage(container, fileName, parser) - TYPE_PAGE_COLLECTION -> PageCollectionPage(container, fileName, parser) else -> { val message = "Unrecognized page type: <${parser.namespace}:${parser.name} type=$type>" Logger.e(message, UnsupportedOperationException(message), "Page") diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt index 73795f5bc..a7997720f 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt @@ -1,10 +1,15 @@ package org.cru.godtools.shared.tool.parser.model.page import kotlin.reflect.KClass +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll +import kotlinx.coroutines.coroutineScope 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.HasPages import org.cru.godtools.shared.tool.parser.model.XMLNS_ANALYTICS +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 @@ -13,12 +18,25 @@ class PageCollectionPage : Page, HasPages { internal const val TYPE_PAGE_COLLECTION = "page-collection" private const val XML_PAGES = "pages" + private const val XML_IMPORT = "import" + private const val XML_IMPORT_FILENAME = "filename" + + internal suspend fun parse( + container: HasPages, + fileName: String?, + parser: XmlPullParser, + parseFile: suspend (String) -> XmlPullParser + ) = PageCollectionPage(container, fileName, parser).apply { + buildPagesFromParsedPages(parseFile) + } } override val analyticsEvents: List - override val pages: List + private val parsedPages: List + override var pages: List by setOnce() + private set - internal constructor( + private constructor( container: HasPages, fileName: String?, parser: XmlPullParser @@ -27,7 +45,7 @@ class PageCollectionPage : Page, HasPages { parser.requirePageType(TYPE_PAGE_COLLECTION) analyticsEvents = mutableListOf() - pages = mutableListOf() + parsedPages = mutableListOf() parser.parseChildren { when (parser.namespace) { XMLNS_ANALYTICS -> when (parser.name) { @@ -35,7 +53,7 @@ class PageCollectionPage : Page, HasPages { } XMLNS_PAGE -> when (parser.name) { - XML_PAGES -> pages += parser.parsePages() + XML_PAGES -> parsedPages += parser.parsePages() } } } @@ -50,13 +68,32 @@ class PageCollectionPage : Page, HasPages { XMLNS_PAGE -> when (name) { XML_PAGE -> { parse(this@PageCollectionPage, null, this@parsePages) - ?.takeIf { supportsPageType(it::class) } - ?.let { add(it) } + ?.let { add(PageOrImport(it)) } } + XML_IMPORT -> add(PageOrImport(ref = getAttributeValue(XML_IMPORT_FILENAME))) } } } } + private suspend fun buildPagesFromParsedPages(parseFile: suspend (String) -> XmlPullParser) { + val pageIndex by lazy { manifest.pageXmlFiles.associate { it.name to it.src } } + + pages = coroutineScope { + parsedPages + .map { + it.page?.let { CompletableDeferred(it) } + ?: async { + val pageSrc = it.ref?.let { pageIndex[it] } ?: return@async null + Page.parse(this@PageCollectionPage, it.ref, parseFile(pageSrc), parseFile) + } + } + .awaitAll() + .filterNotNull() + } + } + override fun supportsPageType(type: KClass) = type == ContentPage::class + + private class PageOrImport(val page: Page? = null, val ref: String? = null) } diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/internal/UsesResources.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/internal/UsesResources.kt index e66b24235..f098181d2 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/internal/UsesResources.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/internal/UsesResources.kt @@ -1,8 +1,11 @@ package org.cru.godtools.shared.tool.parser.internal +import org.cru.godtools.shared.tool.parser.xml.XmlPullParser import org.cru.godtools.shared.tool.parser.xml.XmlPullParserFactory abstract class UsesResources(internal val resourcesDir: String? = "model") { + internal val parseFile: suspend (String) -> XmlPullParser = { getTestXmlParser(it) } + internal suspend fun getTestXmlParser(name: String) = TEST_XML_PULL_PARSER_FACTORY.getXmlParser(name)!!.apply { nextTag() } } diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPageTest.kt index a47fe1c53..98225d752 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPageTest.kt @@ -19,12 +19,18 @@ class PageCollectionPageTest : UsesResources("model/page") { private val manifest = Manifest( config = ParserConfig().withSupportedFeatures(FEATURE_PAGE_COLLECTION), type = Manifest.Type.CYOA, + pageXmlFiles = listOf( + Manifest.XmlFile("ref_page_valid", "page_content.xml"), + Manifest.XmlFile("ref_page_invalid", "page_page-collection_imports.xml"), + ), ) // region Parse XML @Test fun testParsePageCollectionPage() = runTest { - assertNotNull(PageCollectionPage(manifest, null, getTestXmlParser("page_page-collection.xml"))) { + assertNotNull( + PageCollectionPage.parse(manifest, null, getTestXmlParser("page_page-collection.xml"), parseFile) + ) { assertEquals(1, it.analyticsEvents.size) assertEquals(1, it.pages.size) assertNotNull(it.pages[0]) { page -> @@ -34,10 +40,22 @@ class PageCollectionPageTest : UsesResources("model/page") { } } + @Test + fun testParsePageCollectionPage_PageImports() = runTest { + assertNotNull( + PageCollectionPage.parse(manifest, null, getTestXmlParser("page_page-collection_imports.xml"), parseFile) + ) { + assertEquals(1, it.analyticsEvents.size) + assertEquals(2, it.pages.size) + assertEquals("embedded_content_page", it.pages[0].id) + assertEquals("content_page", it.pages[1].id) + } + } + @Test fun testParsePageCollectionPageInvalidType() = runTest { assertFailsWith(XmlPullParserException::class) { - PageCollectionPage(manifest, null, getTestXmlParser("page_invalid_type.xml")) + PageCollectionPage.parse(manifest, null, getTestXmlParser("page_invalid_type.xml"), parseFile) } } // endregion Parse XML diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt index f5a505bd0..636aa46cb 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt @@ -8,6 +8,8 @@ import kotlin.test.assertSame import kotlinx.coroutines.test.runTest import org.ccci.gto.support.androidx.test.junit.runners.AndroidJUnit4 import org.ccci.gto.support.androidx.test.junit.runners.RunOnAndroidWith +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.UsesResources import org.cru.godtools.shared.tool.parser.model.AnalyticsEvent import org.cru.godtools.shared.tool.parser.model.Manifest @@ -43,6 +45,35 @@ class PageTest : UsesResources("model/page") { assertNull(Page.parse(Manifest(type = Manifest.Type.TRACT), null, getTestXmlParser("../lesson/page.xml"))) } + @Test + fun testParsePageCollectionPage() = runTest { + val config = ParserConfig().withSupportedFeatures(FEATURE_PAGE_COLLECTION) + assertIs( + Page.parse( + Manifest(config = config, type = Manifest.Type.CYOA), + null, + getTestXmlParser("page_page-collection.xml"), + parseFile, + ), + ) + assertNull( + Page.parse( + Manifest(type = Manifest.Type.CYOA), + null, + getTestXmlParser("page_page-collection.xml"), + parseFile, + ), + ) + assertNull( + Page.parse( + Manifest(config = config, type = Manifest.Type.LESSON), + null, + getTestXmlParser("page_page-collection.xml"), + parseFile, + ), + ) + } + @Test fun testParseTractPage() = runTest { assertIs( diff --git a/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content.xml b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content.xml index 6c7c86751..378ac58de 100644 --- a/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content.xml +++ b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content.xml @@ -1,7 +1,7 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="content" id="content_page"> diff --git a/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_page-collection_imports.xml b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_page-collection_imports.xml new file mode 100644 index 000000000..3831b9f7f --- /dev/null +++ b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_page-collection_imports.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + Text + + + + + + + + + From e16fba4e2edceaa2129c32205cef2896170d827d Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 21 Oct 2024 15:15:55 -0600 Subject: [PATCH 07/13] update Page.controlColor to take the HasPages parent into account --- .../shared/tool/parser/model/page/Page.kt | 10 ++++- .../shared/tool/parser/model/page/PageTest.kt | 43 ++++++++++++++----- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index 8478bbfae..46a941d7b 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -127,6 +127,13 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { } } + private val hasPagesParent: HasPages + get() { + var parent = parent + while (parent !is HasPages) parent = parent?.parent ?: return manifest + return parent + } + val id by lazy { _id ?: fileName ?: "${manifest.code}-$position" } val position by lazy { manifest.pages.indexOf(this) } @@ -168,7 +175,8 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { @Suppress("ktlint:standard:property-naming") // https://github.com/pinterest/ktlint/issues/2448 private val _controlColor: PlatformColor? @get:AndroidColorInt - internal val controlColor get() = _controlColor ?: manifest.pageControlColor + internal val controlColor: PlatformColor + get() = _controlColor ?: (hasPagesParent as? Page)?.controlColor ?: manifest.pageControlColor @AndroidColorInt private val _cardBackgroundColor: PlatformColor? diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt index 636aa46cb..7ae65100d 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt @@ -1,5 +1,6 @@ package org.cru.godtools.shared.tool.parser.model.page +import kotlin.reflect.KClass import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertIs @@ -12,6 +13,7 @@ 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.UsesResources import org.cru.godtools.shared.tool.parser.model.AnalyticsEvent +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.PlatformColor import org.cru.godtools.shared.tool.parser.model.TestColors @@ -97,11 +99,25 @@ class PageTest : UsesResources("model/page") { } // endregion Page.parse() + // region Property: controlColor + @Test + fun testPropertyControlColor() { + val manifest = Manifest(pageControlColor = TestColors.GREEN) + val hasPagesParent = TestPage(parent = manifest, controlColor = TestColors.BLUE) + + assertEquals(TestColors.RED, TestPage(manifest, controlColor = TestColors.RED).controlColor) + assertEquals(TestColors.RED, TestPage(hasPagesParent, controlColor = TestColors.RED).controlColor) + assertEquals(TestColors.GREEN, TestPage(manifest, controlColor = null).controlColor) + assertEquals(TestColors.GREEN, TestPage(TestPage(manifest, controlColor = null)).controlColor) + assertEquals(TestColors.BLUE, TestPage(hasPagesParent, controlColor = null).controlColor) + } + // endregion Property: controlColor + // region Property: multiselectOptionBackgroundColor @Test fun testPropertyMultiselectOptionBackgroundColor() { val page = TestPage( - manifest = Manifest(multiselectOptionBackgroundColor = TestColors.RED), + parent = Manifest(multiselectOptionBackgroundColor = TestColors.RED), multiselectOptionBackgroundColor = TestColors.GREEN, ) assertEquals(TestColors.GREEN, page.multiselectOptionBackgroundColor) @@ -110,7 +126,7 @@ class PageTest : UsesResources("model/page") { @Test fun testPropertyMultiselectOptionBackgroundColorFallback() { val page = TestPage( - manifest = Manifest(multiselectOptionBackgroundColor = TestColors.GREEN), + parent = Manifest(multiselectOptionBackgroundColor = TestColors.GREEN), multiselectOptionBackgroundColor = null, ) assertEquals(TestColors.GREEN, page.multiselectOptionBackgroundColor) @@ -121,7 +137,7 @@ class PageTest : UsesResources("model/page") { @Test fun testPropertyMultiselectOptionSelectedColor() { val page = TestPage( - manifest = Manifest(multiselectOptionSelectedColor = TestColors.RED), + parent = Manifest(multiselectOptionSelectedColor = TestColors.RED), multiselectOptionSelectedColor = TestColors.GREEN, ) assertEquals(TestColors.GREEN, page.multiselectOptionSelectedColor) @@ -130,7 +146,7 @@ class PageTest : UsesResources("model/page") { @Test fun testPropertyMultiselectOptionSelectedColorFallback() { val page = TestPage( - manifest = Manifest(multiselectOptionSelectedColor = TestColors.GREEN), + parent = Manifest(multiselectOptionSelectedColor = TestColors.GREEN), multiselectOptionSelectedColor = null, ) assertEquals(TestColors.GREEN, page.multiselectOptionSelectedColor) @@ -179,13 +195,20 @@ class PageTest : UsesResources("model/page") { // endregion Property: previousPage private class TestPage( - manifest: Manifest = Manifest(), + parent: HasPages = Manifest(), + controlColor: PlatformColor? = null, multiselectOptionBackgroundColor: PlatformColor? = null, multiselectOptionSelectedColor: PlatformColor? = null, override val analyticsEvents: List = emptyList(), - ) : Page( - container = manifest, - multiselectOptionBackgroundColor = multiselectOptionBackgroundColor, - multiselectOptionSelectedColor = multiselectOptionSelectedColor, - ) + override val pages: List = emptyList(), + ) : + Page( + container = parent, + controlColor = controlColor, + multiselectOptionBackgroundColor = multiselectOptionBackgroundColor, + multiselectOptionSelectedColor = multiselectOptionSelectedColor, + ), + HasPages { + override fun supportsPageType(type: KClass) = true + } } From 33d6b50dad12179d450cd699e5041d4a479fe3fa Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 21 Oct 2024 15:46:47 -0600 Subject: [PATCH 08/13] update cardBackgroundColor to properly fallback --- .../shared/tool/parser/model/page/Page.kt | 2 +- .../shared/tool/parser/model/page/PageTest.kt | 16 ++++++++++++++++ .../tool/parser/model/tract/TractPageTest.kt | 7 ------- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index 46a941d7b..899036e35 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -181,7 +181,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { @AndroidColorInt private val _cardBackgroundColor: PlatformColor? @get:AndroidColorInt - override val cardBackgroundColor get() = _cardBackgroundColor ?: manifest.cardBackgroundColor + override val cardBackgroundColor get() = _cardBackgroundColor ?: super.cardBackgroundColor private val _multiselectOptionBackgroundColor: PlatformColor? override val multiselectOptionBackgroundColor diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt index 7ae65100d..45656acbc 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt @@ -99,6 +99,20 @@ class PageTest : UsesResources("model/page") { } // endregion Page.parse() + // region Property: cardBackgroundColor + @Test + fun testPropertyCardBackgroundColor() { + val manifest = Manifest(cardBackgroundColor = TestColors.GREEN) + val hasPagesParent = TestPage(parent = manifest, cardBackgroundColor = TestColors.BLUE) + + assertEquals(TestColors.RED, TestPage(manifest, cardBackgroundColor = TestColors.RED).cardBackgroundColor) + assertEquals(TestColors.RED, TestPage(hasPagesParent, cardBackgroundColor = TestColors.RED).cardBackgroundColor) + assertEquals(TestColors.GREEN, TestPage(manifest, cardBackgroundColor = null).cardBackgroundColor) + assertEquals(TestColors.GREEN, TestPage(TestPage(manifest, cardBackgroundColor = null)).cardBackgroundColor) + assertEquals(TestColors.BLUE, TestPage(hasPagesParent, cardBackgroundColor = null).cardBackgroundColor) + } + // endregion Property: cardBackgroundColor + // region Property: controlColor @Test fun testPropertyControlColor() { @@ -196,6 +210,7 @@ class PageTest : UsesResources("model/page") { private class TestPage( parent: HasPages = Manifest(), + cardBackgroundColor: PlatformColor? = null, controlColor: PlatformColor? = null, multiselectOptionBackgroundColor: PlatformColor? = null, multiselectOptionSelectedColor: PlatformColor? = null, @@ -204,6 +219,7 @@ class PageTest : UsesResources("model/page") { ) : Page( container = parent, + cardBackgroundColor = cardBackgroundColor, controlColor = controlColor, multiselectOptionBackgroundColor = multiselectOptionBackgroundColor, multiselectOptionSelectedColor = multiselectOptionSelectedColor, diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPageTest.kt index df7b6dc63..e63ee019c 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/tract/TractPageTest.kt @@ -104,13 +104,6 @@ class TractPageTest : UsesResources("model/tract") { } } - @Test - fun testCardBackgroundColorFallbackBehavior() { - val manifest = Manifest(cardBackgroundColor = TestColors.BLUE) - assertEquals(TestColors.GREEN, TractPage(manifest, cardBackgroundColor = TestColors.GREEN).cardBackgroundColor) - assertEquals(manifest.cardBackgroundColor, TractPage(manifest).cardBackgroundColor) - } - @Test fun testCardTextColorBehavior() { with(TractPage(textColor = TestColors.GREEN)) { From d48addf954250ecd760e730064228a201bbe5e2e Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 21 Oct 2024 16:25:29 -0600 Subject: [PATCH 09/13] update Page.position to support arbitrary hasPagesParents --- .../shared/tool/parser/model/page/Page.kt | 2 +- .../shared/tool/parser/model/page/PageTest.kt | 29 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index 899036e35..21052ec83 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -135,7 +135,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { } val id by lazy { _id ?: fileName ?: "${manifest.code}-$position" } - val position by lazy { manifest.pages.indexOf(this) } + val position by lazy { hasPagesParent.pages.indexOf(this) } private val _id: String? @VisibleForTesting diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt index 45656acbc..2f6d4132a 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt @@ -99,6 +99,32 @@ class PageTest : UsesResources("model/page") { } // endregion Page.parse() + // region Property: position + @Test + fun testPosition_manifest() { + val manifest = Manifest( + pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2")) } + ) + + val page1 = manifest.findPage("page1")!! + val page2 = manifest.findPage("page2")!! + assertEquals(0, page1.position) + assertEquals(1, page2.position) + } + + @Test + fun testPosition_hasPagesParent() { + val parent = TestPage( + pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2")) } + ) + + val page1 = parent.findPage("page1")!! + val page2 = parent.findPage("page2")!! + assertEquals(0, page1.position) + assertEquals(1, page2.position) + } + // endregion Property: position + // region Property: cardBackgroundColor @Test fun testPropertyCardBackgroundColor() { @@ -215,7 +241,7 @@ class PageTest : UsesResources("model/page") { multiselectOptionBackgroundColor: PlatformColor? = null, multiselectOptionSelectedColor: PlatformColor? = null, override val analyticsEvents: List = emptyList(), - override val pages: List = emptyList(), + pages: ((HasPages) -> List?)? = null, ) : Page( container = parent, @@ -225,6 +251,7 @@ class PageTest : UsesResources("model/page") { multiselectOptionSelectedColor = multiselectOptionSelectedColor, ), HasPages { + override val pages: List = pages?.invoke(this).orEmpty() override fun supportsPageType(type: KClass) = true } } From e36e37124bcbbac051dcfdfcbf1fea8bf2346f5e Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Mon, 21 Oct 2024 16:14:28 -0600 Subject: [PATCH 10/13] update parentPage, nextPage, and previousPage to support HasPage parents --- .../shared/tool/parser/model/page/Page.kt | 6 +-- .../shared/tool/parser/model/page/PageTest.kt | 41 +++++++++++++++++-- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index 21052ec83..fedb62115 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -142,9 +142,9 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { internal val fileName: String? private val _parentPage: String? - val parentPage get() = manifest.findPage(_parentPage) - val nextPage get() = manifest.pages.getOrNull(position + 1) - val previousPage get() = manifest.pages.getOrNull(position - 1) + val parentPage get() = hasPagesParent.findPage(_parentPage) + val nextPage get() = hasPagesParent.pages.getOrNull(position + 1) + val previousPage get() = hasPagesParent.pages.getOrNull(position - 1) val isHidden: Boolean diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt index 2f6d4132a..4cbafe6c6 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt @@ -195,7 +195,7 @@ class PageTest : UsesResources("model/page") { // region Property: parentPage @Test - fun testParentPage() { + fun testParentPage_manifest() { val manifest = Manifest( pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2", parentPage = "page1")) } ) @@ -204,11 +204,22 @@ class PageTest : UsesResources("model/page") { val page2 = manifest.findPage("page2")!! assertSame(page1, page2.parentPage) } + + @Test + fun testParentPage_hasPagesParent() { + val parent = TestPage( + pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2", parentPage = "page1")) } + ) + + val page1 = parent.findPage("page1")!! + val page2 = parent.findPage("page2")!! + assertSame(page1, page2.parentPage) + } // endregion Property: parentPage // region Property: nextPage @Test - fun testNextPage() { + fun testNextPage_manifest() { val manifest = Manifest( pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2")) } ) @@ -218,11 +229,23 @@ class PageTest : UsesResources("model/page") { assertSame(page2, page1.nextPage) assertNull(page2.nextPage) } + + @Test + fun testNextPage_hasPagesParent() { + val parent = TestPage( + pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2")) } + ) + + val page1 = parent.findPage("page1")!! + val page2 = parent.findPage("page2")!! + assertSame(page2, page1.nextPage) + assertNull(page2.nextPage) + } // endregion Property: nextPage // region Property: previousPage @Test - fun testPreviousPage() { + fun testPreviousPage_manifest() { val manifest = Manifest( pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2")) } ) @@ -232,6 +255,18 @@ class PageTest : UsesResources("model/page") { assertSame(page1, page2.previousPage) assertNull(page1.previousPage) } + + @Test + fun testPreviousPage_hasPagesParent() { + val parent = TestPage( + pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2")) } + ) + + val page1 = parent.findPage("page1")!! + val page2 = parent.findPage("page2")!! + assertSame(page1, page2.previousPage) + assertNull(page1.previousPage) + } // endregion Property: previousPage private class TestPage( From e3e0b5aeddf7d82916ec97b547d7ed55bd0fb645 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Wed, 23 Oct 2024 10:45:51 -0600 Subject: [PATCH 11/13] support parentPage parameters --- .../shared/tool/parser/model/page/Page.kt | 20 +++-- .../shared/tool/parser/model/page/PageTest.kt | 90 ++++++++++++++++++- 2 files changed, 102 insertions(+), 8 deletions(-) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index fedb62115..1d3bdcbbf 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -127,7 +127,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { } } - private val hasPagesParent: HasPages + private val parentPageContainer: HasPages get() { var parent = parent while (parent !is HasPages) parent = parent?.parent ?: return manifest @@ -135,16 +135,24 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { } val id by lazy { _id ?: fileName ?: "${manifest.code}-$position" } - val position by lazy { hasPagesParent.pages.indexOf(this) } + val position by lazy { parentPageContainer.pages.indexOf(this) } private val _id: String? @VisibleForTesting internal val fileName: String? private val _parentPage: String? - val parentPage get() = hasPagesParent.findPage(_parentPage) - val nextPage get() = hasPagesParent.pages.getOrNull(position + 1) - val previousPage get() = hasPagesParent.pages.getOrNull(position - 1) + val parentPage get() = parentPageContainer.findPage(_parentPage?.substringBefore("?")) + val parentPageParams get() = when { + parentPage == null -> emptyMap() + else -> _parentPage.orEmpty().substringAfter("?", "") + .split("&") + .mapNotNull { it.split("=", limit = 2).takeIf { it.size == 2 } } + .associate { (key, value) -> key to value } + } + + val nextPage get() = parentPageContainer.pages.getOrNull(position + 1) + val previousPage get() = parentPageContainer.pages.getOrNull(position - 1) val isHidden: Boolean @@ -176,7 +184,7 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { private val _controlColor: PlatformColor? @get:AndroidColorInt internal val controlColor: PlatformColor - get() = _controlColor ?: (hasPagesParent as? Page)?.controlColor ?: manifest.pageControlColor + get() = _controlColor ?: (parentPageContainer as? Page)?.controlColor ?: manifest.pageControlColor @AndroidColorInt private val _cardBackgroundColor: PlatformColor? diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt index 4cbafe6c6..92ce89f65 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt @@ -215,8 +215,90 @@ class PageTest : UsesResources("model/page") { val page2 = parent.findPage("page2")!! assertSame(page1, page2.parentPage) } + + @Test + fun testParentPage_restrictToCurrentContainer() { + val manifest = Manifest( + pages = { + listOf( + TestPage(it, id = "page1") { + listOf( + TestPage(it, id = "page1_1"), + + TestPage(it, id = "test1", parentPage = "page1_1"), + TestPage(it, id = "test2", parentPage = "page2"), + ) + }, + TestPage(it, id = "page2"), + + // parentPage tests + TestPage(it, id = "test3", parentPage = "page1"), + TestPage(it, id = "test4", parentPage = "page1_1"), + ) + }, + ) + val page1 = manifest.findPage("page1") as TestPage + val page11 = page1.findPage("page1_1")!! + + assertSame(page11, page1.findPage("test1")!!.parentPage) + assertNull(page1.findPage("test2")!!.parentPage, "page2 is not in the same page container as test2") + assertSame(page1, manifest.findPage("test3")!!.parentPage) + assertNull(manifest.findPage("test4")!!.parentPage, "page1_1 is not in the same page container as test4") + } + + @Test + fun testParentPage_hasParams() { + val manifest = Manifest( + pages = { + listOf( + TestPage(it, id = "page1"), + + // parentPage tests + TestPage(it, id = "test1", parentPage = "page1"), + TestPage(it, id = "test2", parentPage = "page1?active-page=page1_2"), + TestPage(it, id = "test3", parentPage = "page1?active-page=page2"), + TestPage(it, id = "test4", parentPage = "missing?active-page=page2"), + ) + }, + ) + val page1 = manifest.findPage("page1")!! + + assertSame(page1, manifest.findPage("test1")!!.parentPage) + assertSame(page1, manifest.findPage("test2")!!.parentPage) + assertSame(page1, manifest.findPage("test3")!!.parentPage) + assertNull(manifest.findPage("test4")!!.parentPage, "missing doesn't exist") + } // endregion Property: parentPage + // region Property: parentPageParams + @Test + fun testParentPageParams() { + val manifest = Manifest( + pages = { + listOf( + TestPage(it, id = "page1"), + + TestPage(it, id = "test1", parentPage = "page1"), + TestPage(it, id = "test2", parentPage = "page1?active-page=page1_2"), + TestPage(it, id = "test3", parentPage = "page1?a=1&c=3&b=2"), + TestPage(it, id = "test4", parentPage = null), + TestPage(it, id = "test5", parentPage = "missing?active-page=page2"), + ) + }, + ) + + assertEquals(emptyMap(), manifest.findPage("test1")!!.parentPageParams) + assertEquals(mapOf("active-page" to "page1_2"), manifest.findPage("test2")!!.parentPageParams) + assertEquals(mapOf("a" to "1", "b" to "2", "c" to "3"), manifest.findPage("test3")!!.parentPageParams) + assertEquals(emptyMap(), manifest.findPage("test4")!!.parentPageParams) + assertEquals( + emptyMap(), + manifest.findPage("test5")!!.parentPageParams, + "Don't parse parameters if the parentPage doesn't exist", + ) + } + // endregion Property: parentPageParams + // region Property: nextPage @Test fun testNextPage_manifest() { @@ -271,22 +353,26 @@ class PageTest : UsesResources("model/page") { private class TestPage( parent: HasPages = Manifest(), + id: String? = null, + parentPage: String? = null, cardBackgroundColor: PlatformColor? = null, controlColor: PlatformColor? = null, multiselectOptionBackgroundColor: PlatformColor? = null, multiselectOptionSelectedColor: PlatformColor? = null, override val analyticsEvents: List = emptyList(), - pages: ((HasPages) -> List?)? = null, + pages: ((HasPages) -> List) = { listOf() }, ) : Page( container = parent, + id = id, + parentPage = parentPage, cardBackgroundColor = cardBackgroundColor, controlColor = controlColor, multiselectOptionBackgroundColor = multiselectOptionBackgroundColor, multiselectOptionSelectedColor = multiselectOptionSelectedColor, ), HasPages { - override val pages: List = pages?.invoke(this).orEmpty() + override val pages: List = pages(this) override fun supportsPageType(type: KClass) = true } } From 3934d73f68ee6548eb7dd59c9f2993b83dbd3b96 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Wed, 23 Oct 2024 15:40:41 -0600 Subject: [PATCH 12/13] add support for parsing the parent page override attribute this is meant as a temporary workaround to allow older versions of the parser to continue to depend upon the parent attribute --- .../shared/tool/parser/model/page/Page.kt | 8 ++++- .../shared/tool/parser/model/page/PageTest.kt | 34 +++++++++++++++++++ .../parser/model/page/page_content_parent.xml | 6 ++++ .../page/page_content_parent_override.xml | 6 ++++ 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content_parent.xml create mode 100644 module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content_parent_override.xml diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt index 1d3bdcbbf..dfe69ce10 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/Page.kt @@ -9,6 +9,7 @@ import kotlin.native.HiddenFromObjC import org.ccci.gto.support.androidx.annotation.RestrictTo import org.ccci.gto.support.androidx.annotation.RestrictToScope import org.ccci.gto.support.androidx.annotation.VisibleForTesting +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.model.AnalyticsEvent import org.cru.godtools.shared.tool.parser.model.AnalyticsEvent.Trigger @@ -72,6 +73,8 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { internal companion object { internal const val XML_PAGE = "page" + private const val XML_PARENT_PAGE_COLLECTION_OVERRIDE = "parent_override_page-collection" + @AndroidColorInt @VisibleForTesting internal val DEFAULT_BACKGROUND_COLOR = color(0, 0, 0, 0.0) @@ -210,7 +213,10 @@ abstract class Page : BaseModel, Styles, HasAnalyticsEvents { _id = parser.getAttributeValue(XML_ID) this.fileName = fileName - _parentPage = parser.getAttributeValue(XMLNS_CYOA, XML_PARENT) + _parentPage = + parser.getAttributeValue(XMLNS_CYOA, XML_PARENT_PAGE_COLLECTION_OVERRIDE) + ?.takeIf { manifest.config.supportsFeature(FEATURE_PAGE_COLLECTION) } + ?: parser.getAttributeValue(XMLNS_CYOA, XML_PARENT) isHidden = parser.getAttributeValue(XML_HIDDEN)?.toBoolean() ?: false diff --git a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt index 92ce89f65..4d5f3318a 100644 --- a/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt +++ b/module/parser/src/commonTest/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageTest.kt @@ -4,6 +4,7 @@ import kotlin.reflect.KClass import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertIs +import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertSame import kotlinx.coroutines.test.runTest @@ -97,6 +98,39 @@ class PageTest : UsesResources("model/page") { assertNull(Page.parse(Manifest(type = it), null, getTestXmlParser("page_invalid_namespace.xml"))) } } + + @Test + fun testParseParentPage() = runTest { + val manifest = Manifest( + type = Manifest.Type.CYOA, + pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2")) } + ) + assertNotNull(Page.parse(manifest, null, getTestXmlParser("page_content_parent.xml"))) { + assertSame(manifest.findPage("page1"), it.parentPage) + assertEquals(mapOf("param" to "value"), it.parentPageParams) + } + assertNotNull(Page.parse(manifest, null, getTestXmlParser("page_content_parent_override.xml"))) { + assertSame(manifest.findPage("page1"), it.parentPage) + assertEquals(mapOf("param" to "value"), it.parentPageParams) + } + } + + @Test + fun testParseParentPage_pageCollection() = runTest { + val manifest = Manifest( + config = ParserConfig().withSupportedFeatures(FEATURE_PAGE_COLLECTION), + type = Manifest.Type.CYOA, + pages = { listOf(ContentPage(it, id = "page1"), ContentPage(it, id = "page2")) }, + ) + assertNotNull(Page.parse(manifest, null, getTestXmlParser("page_content_parent.xml"))) { + assertSame(manifest.findPage("page1"), it.parentPage) + assertEquals(mapOf("param" to "value"), it.parentPageParams) + } + assertNotNull(Page.parse(manifest, null, getTestXmlParser("page_content_parent_override.xml"))) { + assertSame(manifest.findPage("page2"), it.parentPage) + assertEquals(mapOf("param" to "value2"), it.parentPageParams) + } + } // endregion Page.parse() // region Property: position diff --git a/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content_parent.xml b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content_parent.xml new file mode 100644 index 000000000..b9b74e2fc --- /dev/null +++ b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content_parent.xml @@ -0,0 +1,6 @@ + + + diff --git a/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content_parent_override.xml b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content_parent_override.xml new file mode 100644 index 000000000..2f3a03cac --- /dev/null +++ b/module/parser/src/commonTest/resources/org/cru/godtools/shared/tool/parser/model/page/page_content_parent_override.xml @@ -0,0 +1,6 @@ + + + From 7311a039f8e00c247eb1dea3132fc0477cb48c43 Mon Sep 17 00:00:00 2001 From: Daniel Frett Date: Wed, 23 Oct 2024 15:41:49 -0600 Subject: [PATCH 13/13] add a constant for the active-page parent parameter --- .../shared/tool/parser/model/page/PageCollectionPage.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt index a7997720f..0bb5d747d 100644 --- a/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt +++ b/module/parser/src/commonMain/kotlin/org/cru/godtools/shared/tool/parser/model/page/PageCollectionPage.kt @@ -21,6 +21,8 @@ class PageCollectionPage : Page, HasPages { private const val XML_IMPORT = "import" private const val XML_IMPORT_FILENAME = "filename" + const val PARENT_PARAM_ACTIVE_PAGE = "active-page" + internal suspend fun parse( container: HasPages, fileName: String?,