Jetpack Compose ᴺᴱᵂ
The spotim-compose module provides two Composables — PreConversation and Conversation — that wrap the SDK's Fragment-based API for Jetpack Compose apps. Both composables handle the Fragment lifecycle internally so you do not need to interact with FragmentManager directly.
| Composable | Description |
|---|---|
PreConversation | Pre-conversation teaser showing comment count and top comments. Opens the full conversation on tap. |
Conversation | Full conversation experience with threaded comments and comment input. |
PrerequisitesAssign your
spotIdbefore using any composables. YourspotIdis provided by your OpenWeb PSM.OpenWeb.manager.spotId = "YOUR_SPOT_ID"
Add the Dependency
Add the compose module to your app's build.gradle. Use the same version as the core SDK.
implementation 'io.github.spotim:spotim-compose:3.0.0'Required Activity Setup
The Conversation composable requires specific window configuration to keep the comment input visible above the soft keyboard. Apply all three steps to the activity that hosts the composable.
Note: PreConversation does not host a text input, so this setup is only required when using Conversation.
- Set
windowSoftInputModein yourAndroidManifest.xml:
<activity
android:name=".YourActivity"
android:windowSoftInputMode="adjustResize" />Note: adjustResize is required on API 29 and below, where WindowInsets.ime is only reported when this flag is set. On API 30 and above, enableEdgeToEdge() handles keyboard insets automatically, but having adjustResize set is harmless.
- Call
enableEdgeToEdge()in your activity'sonCreate:
class YourActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
YourTheme {
// your composable tree
}
}
}
}- Apply window insets padding on the root Compose container:
Box(
modifier = Modifier
.padding(
WindowInsets.ime
.union(WindowInsets.systemBars)
.asPaddingValues()
)
.consumeWindowInsets(WindowInsets.systemBars)
) {
// your content
}Important: Do NOT add Modifier.imePadding() anywhere in the Compose tree when using the Conversation composable. Adding it causes double-padding and breaks keyboard handling.
PreConversation
Displays the pre-conversation teaser — comment count, top comments, and a prompt to open the full conversation. Embed it in article feeds or detail screens.
import spotIm.compose.PreConversation
PreConversation(
postId = "POST_ID",
onError = { exception ->
// fires if the host is not a FragmentActivity, or if the fragment fails to load
}
)Parameters
| Parameter | Purpose |
|---|---|
postId | Identifies the content item, matching the post ID used in your CMS. (String, required) |
modifier | Applied to the root container of the composable. (Modifier, default Modifier) |
articleSettings | Article metadata source. Defaults to fetching from the OpenWeb backend. (OWArticleSettings, default OWArticleSettings()) |
additionalSettings | Behavioural overrides for the pre-conversation. (OWAdditionalSettings, default OWAdditionalSettings()) |
conversationNavigationOptions | Controls how the full conversation opens when the user taps. (OWConversationNavigationOptions, default ConversationFullScreen()) |
onError | Called on the main thread if the host is not a FragmentActivity or the fragment fails to load. ((SpotException) -> Unit?, default null) |
Navigation modes
| Option | Behaviour |
|---|---|
OWConversationNavigationOptions.ConversationFullScreen() | SDK opens the full conversation full-screen (default). Pass an optional OWFlowActionsCallbacks to receive action events. |
OWConversationNavigationOptions.ConversationCustom(preConversationActionsCallbacks) | You handle the transition. Implement OWPreConversationActionsCallbacks.openConversationFlow(route) to push your own screen. |
// Default: SDK manages navigation
PreConversation(postId = "POST_ID")
// Custom: you handle the transition
PreConversation(
postId = "POST_ID",
conversationNavigationOptions = OWConversationNavigationOptions.ConversationCustom(
preConversationActionsCallbacks = object : OWPreConversationActionsCallbacks {
override fun openConversationFlow(route: OWConversationRoute) {
// navigate to your own conversation screen, passing route
}
}
)
)Conversation
Embeds the full conversation experience inline in your Compose layout. Apply the required activity setup above before using this composable.
import spotIm.compose.Conversation
Conversation(
postId = "POST_ID",
onError = { exception ->
// fires if the host is not a FragmentActivity, or if the fragment fails to load
}
)Parameters
| Parameter | Purpose |
|---|---|
postId | Identifies the content item, matching the post ID used in your CMS. (String, required) |
modifier | Applied to the root container of the composable. (Modifier, default Modifier) |
articleSettings | Article metadata source. Defaults to fetching from the OpenWeb backend. (OWArticleSettings, default OWArticleSettings()) |
route | Deep-links to a specific entry point within the conversation. (OWConversationRoute?, default null) |
additionalSettings | Behavioural overrides for the conversation. (OWAdditionalSettings, default OWAdditionalSettings()) |
onAction | Called on the main thread for SDK-level action events. ((OWFlowActionCallbackType, OWFlowSourceType, OWPostId) -> Unit?, default null) |
onError | Called on the main thread if the host is not a FragmentActivity or the fragment fails to load. ((SpotException) -> Unit?, default null) |
Route options
Pass a route to deep-link the conversation to a specific entry point on load.
| Route | Purpose |
|---|---|
null | Opens the conversation at the top (default). |
OWConversationRoute.OWCommentThreadRoute(commentId) | Scrolls to a specific comment thread. |
OWConversationRoute.OWCommentCreationRoute(type) | Opens the comment editor. Pass OWCommentCreationType.Comment for a new top-level comment. |
// Open a specific comment thread
Conversation(
postId = "POST_ID",
route = OWConversationRoute.OWCommentThreadRoute(commentId = "COMMENT_ID")
)
// Open the comment creation screen
Conversation(
postId = "POST_ID",
route = OWConversationRoute.OWCommentCreationRoute(type = OWCommentCreationType.Comment)
)Action callbacks
Use onAction to respond to SDK-level events such as conversation dismissal or publisher profile taps.
OWFlowActionCallbackType | When it fires |
|---|---|
ConversationDismissed | The conversation was dismissed by the user. |
OpenPublisherProfile(context, ssoPublisherId, type) | The user tapped a publisher profile. Use ssoPublisherId to navigate to your own profile screen. |
Conversation(
postId = "POST_ID",
onAction = { actionType, source, postId ->
when (actionType) {
is OWFlowActionCallbackType.OpenPublisherProfile -> {
// navigate to your profile screen using actionType.ssoPublisherId
}
OWFlowActionCallbackType.ConversationDismissed -> {
// conversation was dismissed
}
}
}
)Fragment Lifecycle
Both composables host a Fragment internally. The fragment is preserved across configuration changes (rotation, font size changes) and reattached on recomposition — you do not need to save or restore any state. Changing postId or route across recompositions triggers a fresh fragment load.
