Skip to content

feat: Implement all Compose views#42

Open
sidorchukandrew wants to merge 13 commits intoas/new-kotlin-versionfrom
as/kotlin-widget-view
Open

feat: Implement all Compose views#42
sidorchukandrew wants to merge 13 commits intoas/new-kotlin-versionfrom
as/kotlin-widget-view

Conversation

@sidorchukandrew
Copy link
Copy Markdown
Collaborator

Description

This brings the Android side of the RN SDK up to date with the Swift SDK. There are still a few UI bugs that occur when the components load. However, those can be tackled in future work.

Type of Change

  • feat: New feature (non-breaking change which adds functionality)
  • fix: Bug fix (non-breaking change which fixes an issue)
  • docs: Documentation update
  • refactor: Code refactoring (no functional changes)
  • perf: Performance improvement
  • test: Test additions or updates
  • build: Build system or dependency changes
  • ci: CI configuration changes
  • chore: Other changes (maintenance, etc.)

Checklist

  • My code follows the project's code style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • All commit messages follow conventional commits format
  • I have updated the appropriate section in documentation (if needed)

@sidorchukandrew sidorchukandrew self-assigned this Apr 1, 2026
@sidorchukandrew sidorchukandrew requested a review from mic-mart April 1, 2026 01:20
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 1, 2026

Greptile Summary

This PR brings the Android (Kotlin/Compose) side of the React Native SDK up to parity with the existing Swift SDK. It replaces the old ExpoComposeView subclass pattern with top-level @Composable functions called from the Expo Modules View { } DSL, and swaps placeholder Text views for real SDK composables (BibleReader, BibleText, BibleCard, VerseOfTheDay, SignInWithYouVersionButton). On the TypeScript side, all three shared view components now select between @expo/ui/jetpack-compose and @expo/ui/swift-ui hosts based on Platform.OS, and the example app gains Android tab-bar icons.

Key changes:

  • All five Android view modules migrated from the class-based pattern to the composable function pattern
  • onTap for BibleTextView is now properly dispatched as a VerseTappedEvent carrying the tapped BibleReference
  • VotdView gains showIcon and isCompact props, and onSharePress/onFullChapterPress event callbacks
  • BibleReferenceRecord now carries a nullable verse field, and the new VerseTappedEvent record bridges the Kotlin SDK type to the Expo record layer
  • TypeScript host selection is correctly gated on Platform.OS across BibleTextView, BibleWidgetView, and VotdView
  • One minor typo (footnodeMode) remains in YVPBibleTextView.kt — see inline comment

Confidence Score: 4/5

Safe to merge with awareness that several props (fontFamily, colorScheme on BibleWidget, onTap on SignIn button) are still inert on Android — all acknowledged in prior review threads as deferred work.

The PR makes solid progress converting all five Android views to real SDK composables and correctly wiring events. Previously flagged P1 issues (inert fontFamily, unused isDark, non-functional SignIn onTap) are unresolved but explicitly deferred by the developer. The one new finding is a trivial typo (P2). Score is 4 rather than 5 to flag the known deferred gaps for completeness.

android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleTextView.kt — typo and hardcoded fontFamily; android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleWidgetView.kt — isDark computed but unused

Important Files Changed

Filename Overview
android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleTextView.kt Converted from class to composable function; wires up onVerseTap callback; contains a typo in footnodeMode and fontFamily is still hardcoded to FontFamily.Serif.
android/src/main/java/com/youversion/reactnativesdk/views/YVPBibleWidgetView.kt Converted from class to composable function; replaces placeholder Text with real BibleCard; isDark is computed but still not passed to BibleCard.
android/src/main/java/com/youversion/reactnativesdk/views/YVPVotdView.kt Replaces placeholder with real VerseOfTheDay/CompactVerseOfTheDay composables; adds showIcon and isCompact props; bibleVersionId fallback is consistent with props default (3034).
android/src/main/java/com/youversion/reactnativesdk/views/YVPSignInWithYouVersionButton.kt Converted to top-level composable; onTap is accepted as a parameter but not forwarded to SignInWithYouVersionButton (deferred to future auth work per PR thread).
android/src/main/java/com/youversion/reactnativesdk/api/YVPRecords.kt Adds VerseTappedEvent record and nullable verse field to BibleReferenceRecord; straightforward and correct.
android/src/main/java/com/youversion/reactnativesdk/RNBibleTextViewModule.kt Migrated to new composable View DSL; properly wires EventDispatcher<VerseTappedEvent> and forwards it to YVPBibleTextView.
src/components/BibleTextView.tsx Switches to platform-specific Host components; adds MATCH_CONTENTS constant and AndroidHost support alongside existing iOS host.
example/App.tsx Adds Android tab bar icons via Platform.OS check; uses require()d local assets for Android and SF Symbols for iOS.

Sequence Diagram

sequenceDiagram
    participant JS as React Native (JS/TS)
    participant Host as PlatformHost (AndroidHost)
    participant Module as RN*Module (Expo DSL)
    participant View as @Composable View Fn
    participant SDK as YouVersion Platform SDK

    JS->>Host: render BibleTextView bibleReference onPress
    Host->>Module: props via ComposeProps
    Module->>View: YVPBibleTextView(props, onTap)
    View->>SDK: BibleText(reference, textOptions, onVerseTap)
    SDK-->>View: user taps verse → BibleReference
    View-->>Module: onTap(VerseTappedEvent(reference))
    Module-->>JS: onTap event dispatched to JS

    JS->>Host: render VotdView isCompact=false
    Host->>Module: VotdViewProps
    Module->>View: YVPVotdView(props, onSharePress, onFullChapterPress)
    View->>SDK: VerseOfTheDay(bibleVersionId, dark, onShareClick, onFullChapterClick)
    SDK-->>View: user taps share
    View-->>Module: onSharePress(Unit)
    Module-->>JS: onSharePress event dispatched
Loading

Reviews (3): Last reviewed commit: "chore: update default Bible version to 3..." | Re-trigger Greptile

Comment on lines +37 to +43
@Composable
fun YVPBibleTextView(props: BibleTextViewProps, onTap: () -> Unit) {
BibleText(
reference = bibleReference(props),
textOptions = textOptions(props)
)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 onTap callback is never forwarded to BibleText

The onTap: () -> Unit parameter is accepted by YVPBibleTextView but is silently dropped — it is never passed to the underlying BibleText composable. As a result, the onTap event wired up in RNBibleTextViewModule will never fire for JS consumers.

If BibleText exposes a tap/click parameter, it should be passed through here. If it doesn't, this parameter (and the corresponding Events("onTap") declaration in the module) should be removed until the SDK supports it.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sidorchukandrew I think this is legit

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure about implementing it in this PR because of some difference between what Kotlin and Swift have, but I've decided to add at least the base here: e89f49a

Comment on lines +22 to +33
fun YVPSignInWithYouVersionButton(
props: SignInWithYouVersionButtonProps,
onTap: () -> Unit
) {
SignInWithYouVersionButton(
mode = mode(props),
stroked = stroked(props),
shape = shape(props),
dark = isDark(props),
permissions = { HashSet() }
)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 onTap callback is never forwarded to SignInWithYouVersionButton

The onTap: () -> Unit parameter is accepted but never used when calling SignInWithYouVersionButton(...). The onTap event dispatched from RNSignInWithYouVersionButtonModule will therefore never reach JS consumers — effectively making the button's tap event non-functional on Android.

If the SDK's SignInWithYouVersionButton exposes an onClick or similar parameter, wire onTap through to it. If it currently doesn't, this should be documented and the Events("onTap") declaration in the module should be deferred until it's supported.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sidorchukandrew I think this one is legit also

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally think we can leave this as is, because we'll be updating it shortly with the auth work Brenden did. If you'd like, I can add some short-lived documentation like greptile said.

Comment on lines +79 to +86
@Composable
fun isDark(props: BibleWidgetViewProps): Boolean {
return when (props.colorScheme.value) {
"dark" -> true
"light" -> false
else -> isSystemInDarkTheme()
}
} No newline at end of file
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 isDark is defined but never used

The isDark(props: BibleWidgetViewProps) composable function is defined and computes the dark/light theme from props.colorScheme, but BibleCard(...) is called without a dark (or equivalent) parameter. The colorScheme prop accepted from React Native has no effect on the rendered widget.

Either pass the result of isDark(props) to BibleCard once it supports a dark parameter, or remove this function until it can be wired up.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the Kotlin side may need to implement this or we scrap this altogether for Swift too. Or we say it's an iOS-only prop.

Copy link
Copy Markdown
Collaborator

@camrun91 camrun91 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few changes and the greptile issues look legit too.

<Host matchContents={MATCH_CONTENTS} style={[styles.wrapper, style]}>
<PlatformHost
matchContents={MATCH_CONTENTS}
style={[style, styles.wrapper]}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are flipped, this one will always take the styles.wrapper

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought I already fixed this somewhere 🤔 Either way, fixed here: 096df82

<Host matchContents={MATCH_CONTENTS} style={[styles.wrapper, style]}>
<PlatformHost
matchContents={MATCH_CONTENTS}
style={[style, styles.wrapper]}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, this will always take the styles.wrapper

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here! 096df82

fun YVPVotdView(props: VotdViewProps, onSharePress: () -> Unit, onFullChapterPress: () -> Unit) {
if (props.isCompact.value == true) {
CompactVerseOfTheDay(
bibleVersionId = props.bibleVersionId.value ?: 111,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default version has changed to 3034

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed here: cecf9a2

@sidorchukandrew sidorchukandrew requested a review from camrun91 April 3, 2026 01:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants