From c1d17e9e6887b9e551f9235aabcdb589f20bb75a Mon Sep 17 00:00:00 2001 From: Michael Martin Date: Sat, 31 Jan 2026 18:17:08 -0600 Subject: [PATCH] feat(android): implement view modules with Kotlin SDK composables Replace placeholder implementations with actual Kotlin SDK composables: - YVPBibleTextView now uses BibleText composable with full prop mapping - YVPVotdView now uses VerseOfTheDay composable - YVPBibleWidgetView now uses BibleWidget composable - YVPBibleReaderView now uses BibleReader composable Co-Authored-By: Claude Opus 4.5 --- .../views/YVPBibleReaderView.kt | 54 +++++++---- .../reactnativesdk/views/YVPBibleTextView.kt | 97 ++++++++++++++++--- .../views/YVPBibleWidgetView.kt | 57 +++++++---- .../reactnativesdk/views/YVPVotdView.kt | 24 ++--- 4 files changed, 163 insertions(+), 69 deletions(-) diff --git a/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleReaderView.kt b/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleReaderView.kt index 3b17ceb..595b71a 100644 --- a/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleReaderView.kt +++ b/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleReaderView.kt @@ -1,17 +1,12 @@ package com.youversion.reactnativesdk.views import android.content.Context -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp +import com.youversion.platform.core.bibles.domain.BibleReference +import com.youversion.platform.reader.BibleReader import expo.modules.kotlin.AppContext import expo.modules.kotlin.views.ComposeProps import expo.modules.kotlin.views.ExpoComposeView @@ -37,18 +32,39 @@ class YVPBibleReaderView(context: Context, appContext: AppContext) : @Composable override fun Content(modifier: Modifier) { - // TODO: Replace with actual BibleReaderView composable when Kotlin SDK is ready - Box( - modifier = modifier - .fillMaxSize() - .padding(16.dp), - contentAlignment = Alignment.Center - ) { - Text( - text = "BibleReaderView placeholder\n" + - "App: ${props.appName.value}\n" + - "Reference: ${props.bookUSFM.value} ${props.chapter.value}", - color = Color.Gray + BibleReader( + appName = props.appName.value ?: "", + appSignInMessage = props.signInMessage.value ?: "", + bibleReference = bibleReference(), + ) + } + + private fun bibleReference(): BibleReference? { + if (props.hasReference.value != true) { + return null + } + + val versionId = props.versionId.value ?: return null + val bookUSFM = props.bookUSFM.value ?: return null + val chapter = props.chapter.value ?: return null + + val verseStart = props.verseStart.value + val verseEnd = props.verseEnd.value + + return if (verseStart != null && verseEnd != null) { + BibleReference( + versionId = versionId, + bookUSFM = bookUSFM, + chapter = chapter, + verseStart = verseStart, + verseEnd = verseEnd, + ) + } else { + BibleReference( + versionId = versionId, + bookUSFM = bookUSFM, + chapter = chapter, + verse = props.verse.value, ) } } diff --git a/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleTextView.kt b/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleTextView.kt index 4e5c223..2a913d2 100644 --- a/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleTextView.kt +++ b/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleTextView.kt @@ -1,16 +1,17 @@ package com.youversion.reactnativesdk.views import android.content.Context -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.unit.sp +import com.youversion.platform.core.bibles.domain.BibleReference +import com.youversion.platform.ui.views.BibleText +import com.youversion.platform.ui.views.BibleTextFootnoteMode +import com.youversion.platform.ui.views.BibleTextOptions import expo.modules.kotlin.AppContext import expo.modules.kotlin.viewevent.EventDispatcher import expo.modules.kotlin.views.ComposeProps @@ -44,17 +45,83 @@ class YVPBibleTextView(context: Context, appContext: AppContext) : @Composable override fun Content(modifier: Modifier) { - // TODO: Replace with actual BibleText composable when Kotlin SDK is ready - Box( - modifier = modifier - .fillMaxWidth() - .padding(16.dp) - ) { - Text( - text = "BibleTextView placeholder - versionId: ${props.versionId.value}, " + - "book: ${props.bookUSFM.value}, chapter: ${props.chapter.value}", - color = Color.Gray + val reference = bibleReference() ?: return + + BibleText( + reference = reference, + textOptions = textOptions(), + onVerseTap = { bibleRef, _ -> + onTap( + mapOf( + "bibleReference" to mapOf( + "versionId" to bibleRef.versionId, + "bookUSFM" to bibleRef.bookUSFM, + "chapter" to bibleRef.chapter, + "verse" to bibleRef.verseStart, + "type" to "verse", + ), + ), + ) + }, + ) + } + + private fun bibleReference(): BibleReference? { + val versionId = props.versionId.value ?: return null + val bookUSFM = props.bookUSFM.value ?: return null + val chapter = props.chapter.value ?: return null + + val verseStart = props.verseStart.value + val verseEnd = props.verseEnd.value + + return if (verseStart != null && verseEnd != null) { + BibleReference( + versionId = versionId, + bookUSFM = bookUSFM, + chapter = chapter, + verseStart = verseStart, + verseEnd = verseEnd, + ) + } else { + BibleReference( + versionId = versionId, + bookUSFM = bookUSFM, + chapter = chapter, + verse = props.verse.value, ) } } + + private fun textOptions(): BibleTextOptions { + return BibleTextOptions( + fontFamily = fontFamily(), + fontSize = (props.fontSize.value ?: 16f).sp, + lineSpacing = props.lineSpacing.value?.sp, + textColor = props.textColor.value?.let { Color(it) }, + wocColor = props.wocColor.value?.let { Color(it) } ?: Color(0xFFFF3D4D), + renderVerseNumbers = props.renderVerseNumbers.value ?: true, + footnoteMode = footnoteMode(), + ) + } + + private fun fontFamily(): FontFamily { + return when (props.fontFamily.value?.lowercase()) { + "serif" -> FontFamily.Serif + "sansserif", "sans-serif" -> FontFamily.SansSerif + "monospace" -> FontFamily.Monospace + "cursive" -> FontFamily.Cursive + else -> FontFamily.Serif + } + } + + private fun footnoteMode(): BibleTextFootnoteMode { + return when (props.footnoteMode.value?.lowercase()) { + "none" -> BibleTextFootnoteMode.NONE + "inline" -> BibleTextFootnoteMode.INLINE + "marker" -> BibleTextFootnoteMode.MARKER + "letters" -> BibleTextFootnoteMode.LETTERS + "image" -> BibleTextFootnoteMode.IMAGE + else -> BibleTextFootnoteMode.NONE + } + } } diff --git a/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleWidgetView.kt b/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleWidgetView.kt index 26c3934..e561748 100644 --- a/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleWidgetView.kt +++ b/android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleWidgetView.kt @@ -2,17 +2,16 @@ package com.youversion.reactnativesdk.views import android.content.Context import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.youversion.platform.core.bibles.domain.BibleReference +import com.youversion.platform.ui.views.widget.BibleWidget import expo.modules.kotlin.AppContext import expo.modules.kotlin.views.ComposeProps import expo.modules.kotlin.views.ExpoComposeView @@ -37,23 +36,47 @@ class YVPBibleWidgetView(context: Context, appContext: AppContext) : @Composable override fun Content(modifier: Modifier) { - val isDark = when (props.colorScheme.value) { + val reference = bibleReference() ?: return + + val isDark = when (props.colorScheme.value?.lowercase()) { "dark" -> true "light" -> false else -> isSystemInDarkTheme() } - // TODO: Replace with actual BibleWidget composable when Kotlin SDK is ready - Box( - modifier = modifier - .fillMaxWidth() - .padding(16.dp) + MaterialTheme( + colorScheme = if (isDark) darkColorScheme() else lightColorScheme(), ) { - Text( - text = "BibleWidgetView placeholder\n" + - "${props.bookUSFM.value} ${props.chapter.value}:${props.verse.value ?: "${props.verseStart.value}-${props.verseEnd.value}"}", - color = if (isDark) Color.White else Color.DarkGray, - fontSize = (props.fontSize.value ?: 23f).sp + BibleWidget( + reference = reference, + fontSize = (props.fontSize.value ?: 23f).sp, + modifier = modifier, + ) + } + } + + private fun bibleReference(): BibleReference? { + val versionId = props.versionId.value ?: return null + val bookUSFM = props.bookUSFM.value ?: return null + val chapter = props.chapter.value ?: return null + + val verseStart = props.verseStart.value + val verseEnd = props.verseEnd.value + + return if (verseStart != null && verseEnd != null) { + BibleReference( + versionId = versionId, + bookUSFM = bookUSFM, + chapter = chapter, + verseStart = verseStart, + verseEnd = verseEnd, + ) + } else { + BibleReference( + versionId = versionId, + bookUSFM = bookUSFM, + chapter = chapter, + verse = props.verse.value, ) } } diff --git a/android/src/main/java/com/youversion/reactnativesdk/views/YVPVotdView.kt b/android/src/main/java/com/youversion/reactnativesdk/views/YVPVotdView.kt index 67465ac..cf4100a 100644 --- a/android/src/main/java/com/youversion/reactnativesdk/views/YVPVotdView.kt +++ b/android/src/main/java/com/youversion/reactnativesdk/views/YVPVotdView.kt @@ -2,16 +2,11 @@ package com.youversion.reactnativesdk.views import android.content.Context import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.unit.dp +import com.youversion.platform.ui.views.votd.VerseOfTheDay import expo.modules.kotlin.AppContext import expo.modules.kotlin.views.ComposeProps import expo.modules.kotlin.views.ExpoComposeView @@ -28,22 +23,15 @@ class YVPVotdView(context: Context, appContext: AppContext) : @Composable override fun Content(modifier: Modifier) { - val isDark = when (props.colorScheme.value) { + val isDark = when (props.colorScheme.value?.lowercase()) { "dark" -> true "light" -> false else -> isSystemInDarkTheme() } - // TODO: Replace with actual VerseOfTheDay composable when Kotlin SDK is ready - Box( - modifier = modifier - .fillMaxWidth() - .padding(16.dp) - ) { - Text( - text = "VotdView placeholder - versionId: ${props.bibleVersionId.value}", - color = if (isDark) Color.White else Color.DarkGray - ) - } + VerseOfTheDay( + bibleVersionId = props.bibleVersionId.value ?: 111, + dark = isDark, + ) } }