Storyteller Jetpack Compose SDK#
This is a developers' guide for setting up Storyteller Compose SDK for native Android apps. This guide will cover the basic technical steps for integrating Storyteller Compose SDK into your app.
Note: While this guide focuses on the Jetpack Compose implementation, corresponding traditional Android Views (e.g., StorytellerStoriesRowView, StorytellerStoriesGridView, StorytellerClipsRowView, StorytellerClipsGridView) also exist and can be used in XML layouts or programmatically. Their configuration attributes and delegate usage are similar to their Compose counterparts.
Getting Started#
Resources#
Showcase examples#
How to Add the SDK to Your Project#
Before you can add the Android SDK to your app, you will need to obtain an API Key. This is a secret key used to authenticate the SDK in your app. Throughout this document it will be marked as [APIKEY].
SDK Installation#
The Compose SDK can be included in your project using Gradle. It is recommended to use Android Studio. If you are having problems with configuring your build, check out the Android Studio guide or Gradle guides.
Note: Starting from 9.3.0 SDK version Compose is now part of the SDK and there is no need to add separate Compose dependency.
The steps to add the SDK are in the Getting Started documentation
Usage#
- At first we will need a nesting composable. You can use any composable layout you want:
Box,Column,LazyColumn, etc.
@Composable
fun MainScreen() {
Box() {
// ...
}
}
- Storyteller Composables Now it's time to add the Storyteller Composables to your app. The Storyteller Composables are the building blocks of the Storyteller SDK.
StorytellerStoriesRow(
modifier = Modifier,
dataModel = StorytellerStoriesDataModel(categories = emptyList()), // data model with the configuration for your Composables. We will describe how to use StorytellerDataModel below.
delegate = listViewDelegate, // delegate for the Composables. We will describe how to use StorytellerListViewDelegate below.
state = rememberStorytellerRowState() // state for the Composables. We will describe how to use StorytellerRowState below.
)
We have the following composable types available:
- StorytellerStoriesRow
- StorytellerStoriesGrid
- StorytellerClipsRow
-
StorytellerClipsGrid
-
Using the Storyteller Composables
You can always modify your Composables during recomposition.
Reload Data:
Just like normal composable lists, they have a list state, so as Storyteller lists, they have a state, and we will use it to reload the data. There is an extra parameter state in the Composables, which is set by default. Let's see how it's used:
val state = rememberStorytellerRowState() // or rememberStorytellerGridState() for StorytellerStoriesGrid or StorytellerClipsGrid
StorytellerStoriesRow(
// ...
state = state
)
// At any point in your code you can call `reloadData` method, maybe after doing PTR or after some event.
LaunchedEffect(Unit) {
state.reloadData()
}
- Setting categories and collections, applying themes and styles
You can use StorytellerStoriesDataModel object for configuring your Stories Composables. It has the following properties:
StorytellerStoriesDataModel(
categories = listOf("category1", "category2"), // list of stories categories for the Composable. If you want to use all categories, you can pass an empty list.
theme = UiTheme(), // theme for the Composable. A global theme will be set if no value will be passed here.
uiStyle = StorytellerListViewStyle.LIGHT, // a style of the Composable. It can be AUTO, LIGHT or DARK. AUTO will represent the theme of the app.
displayLimit = 6, // a limit of the stories to be displayed in the Composable. Default is Int.MAX_VALUE.
cellType = StorytellerListViewCellType.SQUARE, // a cell type of the Composable. It can be SQUARE or ROUND.
visibleTiles = null, // a number of visible tiles for rows. Default is null and turned off. If the value is set for greater than 0, the visible tiles will be turned on. The height of the row will be calculated based on the number of visible tiles and if set to eg. 3.5 it will always show three and a half tile independently of the screen size.
offset = 1, // the offset to start displaying stories from a specific position in the collection. Default is 0 (start from beginning).
context = hashMapOf("placementId" to "home_stories", "location" to "Home"), // Optional analytics context containing integrator-defined key-value pairs. See [Analytics](Analytics.md#context) for more details.
)
Note:
StorytellerStoriesGridsupports onlycellType = StorytellerListViewCellType.SQUARE.
You can use StorytellerClipsDataModel object for configuring your Clips Composables. It has the following properties:
StorytellerClipsDataModel(
collection = "collection1", // a string representing your collection of Clips.
theme = UiTheme(), // theme for the Composable. A global theme will be set if no value will be passed here.
uiStyle = StorytellerListViewStyle.LIGHT, // a style of the Composable. It can be AUTO, LIGHT or DARK. AUTO will represent the theme of the app.
displayLimit = 6, // a limit of the clips to be displayed in the Composable. Default is Int.MAX_VALUE.
cellType = StorytellerListViewCellType.SQUARE, // a cell type of the Composable. It can be SQUARE or ROUND.
visibleTiles = null, // a number of visible tiles for rows. Default is null and turned off. If the value is set for greater than 0, the visible tiles will be turned on. The height of the row will be calculated based on the number of visible tiles and if set to eg. 3.5 it will always show three and a half tile independently of the screen size.
offset = 1, // the offset to start displaying clips from a specific position in the collection. Default is 0 (start from beginning).
context = hashMapOf("placementId" to "home_clips", "location" to "Home"), // Optional analytics context containing integrator-defined key-value pairs. See [Analytics](Analytics.md#context) for more details.
)
Note:
StorytellerClipsGridsupports onlycellType = StorytellerListViewCellType.SQUARE.
Storyteller Compose ListView Delegate#
The StorytellerListViewDelegate will provide you necessary callbacks for the state of data inside you Composables.
This delegate is used to track when data load starts, when it completes, when a tile is tapped, and when player was dismissed by user.
We recommend using remember for the delegate's object to avoid creating new ones during recomposition.
val listViewDelegate by remember("your_item_id") {
val value = object : StorytellerListViewDelegate {
override fun onPlayerDismissed() {
// handle player dismissed event
}
override fun onDataLoadStarted() {
// handle loading started event
}
override fun onDataLoadComplete(success: Boolean, error: Error?, dataCount: Int) {
// handle data load complete event
}
override fun onTileTapped(tileType: StorytellerTileType) {
// handle tile tap event - called before the player Activity is opened
// tileType can be either StorytellerTileType.Story or StorytellerTileType.Clip
}
}
mutableStateOf(
value
)
}
StorytellerStoriesRow(
delegate = listViewDelegate,
// ...
)
StorytellerTileType#
The StorytellerTileType is a sealed class that represents the type of tile that was tapped. It contains information about the tapped item and can be one of two types:
StorytellerTileType.Story#
Represents a Story tile that was tapped.
Properties:
id: String- The unique identifier of the storycategories: List<StorytellerCategory>- List of categories that this story belongs to
StorytellerTileType.Clip#
Represents a Clip tile that was tapped.
Properties:
id: String- The unique identifier of the clipcollectionId: String- The collection ID that this clip belongs tocategories: List<StorytellerCategory>- List of categories that this clip belongs to
Example usage:
override fun onTileTapped(tileType: StorytellerTileType) {
when (tileType) {
is StorytellerTileType.Story -> {
val storyId = tileType.id
val categories = tileType.categories
// Handle story tile tap
Log.d("TileTap", "Story tapped: $storyId, categories: $categories")
}
is StorytellerTileType.Clip -> {
val clipId = tileType.id
val collectionId = tileType.collectionId
val categories = tileType.categories
// Handle clip tile tap
Log.d("TileTap", "Clip tapped: $clipId from collection: $collectionId, categories: $categories")
}
}
}
StorytellerStoriesGrid#
The StorytellerStoriesGrid is a Composable with same functionality as the StorytellerStoriesGridView view from the Storyteller SDK.
Usage in Compose#
//Stories Grid
StorytellerStoriesGrid(
modifier = modifier,
dataModel = StorytellerStoriesDataModel(categories = emptyList()),
delegate = listViewDelegate,
state = rememberStorytellerGridState(),
isEnabled = true
)
//Stories Scrollable Grid
StorytellerStoriesGrid(
modifier = modifier,
dataModel = StorytellerStoriesDataModel(categories = emptyList()),
delegate = listViewDelegate,
state = rememberStorytellerGridState(),
isScrollable = true,
isEnabled = true
)
Parameters#
modifier- aModifierobject that will be applied to theStorytellerStoriesGridcomposable.delegate- aStorytellerListViewDelegateobject that will be used to handle data load events and player dismissed event.state- aStorytellerGridStateobject that can be used to reload data and it has a reference to the actual grid state.- the
rememberStorytellerGridState()has two parameters:lazyGridState- aLazyGridStateobject that will be used to handle the state of the grid.enablePullToRefresh- aBooleanflag that indicates if the pull to refresh should be enabled. it's off if the grid is not scrollable. and it's off by default if the grid is scrollable.
isScrollable- aBooleanflag that indicates if the grid is scrollable, iftruethe grid can be put in a non scrollable container. iffalsethe grid can be put in a scrollable container, but a display limit should be set wisely as it wil layout all tiles in the grid.isEnabled- aBooleanflag that indicates if the tile click should be enabled.
StorytellerStoriesRow#
The StorytellerStoriesRow is a Composable with same functionality as the StorytellerStoriesRowView view from the Storyteller SDK.
Usage in Compose#
StorytellerStoriesRow(
modifier = modifier,
dataModel = StorytellerStoriesDataModel(categories = emptyList()),
delegate = listViewDelegate,
state = rememberStorytellerRowState()
)
StorytellerClipsGrid#
The StorytellerClipsGridView is a Composable with same functionality as the StorytellerClipsGridView view from the Storyteller SDK.
Usage in Compose#
//Clips Grid
StorytellerClipsGrid(
modifier = modifier,
dataModel = StorytellerClipsDataModel(collection = "collection"),
delegate = listViewDelegate,
state = rememberStorytellerGridState(),
isScrollable = false,
isEnabled = true
)
//Clips Scrollable Grid
StorytellerClipsGrid(
modifier = modifier,
dataModel = StorytellerClipsDataModel(collection = "collection"),
delegate = listViewDelegate,
state = rememberStorytellerGridState(),
isScrollable = true,
isEnabled = true
)
Parameters#
modifier- aModifierobject that will be applied to theStorytellerClipsGridcomposable.delegate- aStorytellerListViewDelegateobject that will be used to handle data load events and player dismissed event.state- aStorytellerGridStateobject that can be used to reload data and it has a reference to the actual grid state.- the
rememberStorytellerGridState()has two parameters:lazyGridState- aLazyGridStateobject that will be used to handle the state of the grid.enablePullToRefresh- aBooleanflag that indicates if the pull to refresh should be enabled. it's off if the grid is not scrollable. and it's off by default if the grid is scrollable.
isScrollable- aBooleanflag that indicates if the grid is scrollable, iftruethe grid can be put in a non scrollable container. iffalsethe grid can be put in a scrollable container, but a display limit should be set wisely as it will layout all tiles in the grid.isEnabled- aBooleanflag that indicates if the tile click should be enabled.searchInput- an optionalSearchInputobject that can be used to filter clips in the grid.isVisible- aBooleanflag that indicates if the grid should be visible. Defaults to true.
StorytellerClipsRow#
The StorytellerClipsRow is a Composable with same functionality as the StorytellerClipsRowView view from the Storyteller SDK.
Usage in Compose#
StorytellerClipsRow(
modifier = modifier,
dataModel = StorytellerClipsDataModel(collection = "collection"),
delegate = listViewDelegate,
state = rememberStorytellerRowState()
)