A library to make your stories easy to create with Compose. All the logic about stories transitions and shown indicating is implemented. All you need is only to create UI components.
The UI design is entirely up to you - there's no need to pass parameters to expose content details.
UPD: Since the stable version 1.3.9, there is a also an ability to add video stories!
Add this code:
- to your settings.gradle of the project:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}- to your build.gradle of the module of usage:
dependencies {
implementation("com.github.m2-oss.StoriesCompose:stories:1.3.9") // base functionality (mandatory)
implementation("com.github.m2-oss.StoriesCompose:stories-video:1.3.9") // video stories (optional)
}
To create a list of previews:
- prepare the data:
val STORIES_PREVIEW_LIST = listOf(
UiStoriesPreviewData(
id = "id1",
imageData = R.drawable.ic_launcher_background,
title = "1",
),
UiStoriesPreviewData(
id = "video1",
imageData = R.drawable.ic_launcher_foreground,
title = "video1",
)
)- create the list:
@Composable
fun PreviewList(previews: List<UiStoriesPreviewData>, onClick: (String) -> Unit) {
StoriesPreviewList(
previews = previews,
onClick = { onClick(it) }
)
}The result:
To create container for stories:
- prepare the data:
@Composable
private fun createData(
storiesId: String,
previews: List<UiStoriesPreviewData>
): UiStoriesData = UiStoriesData(
storiesId = storiesId,
stories = buildMap {
val ids = previews.map { it.id }
ids.forEach {
put(
it,
buildList {
add(
if (it.contains("video")) {
UiSlidesData.Video(url = "https://cdn.m2.ru/assets/file-upload-server/20fb0b6ebd500608a682c9794a40ae7e.mp4")
} else {
UiSlidesData.Image(duration = 10_000L)
}
)
}
)
}
}
)- create the containers:
@Composable
fun Container(previews: List<UiStoriesPreviewData>, storiesId: String, onFinished: () -> Unit) {
val data = createData(storiesId, previews)
StoriesContainer(
data = data,
onFinished = onFinished
) { stories, slide, progressBar, playerHolder ->
val player = (playerHolder as? ExoPlayerHolder)?.player
Column(modifier = Modifier.fillMaxSize()) {
val video = data.stories[stories]?.get(slide) is UiSlidesData.Video
Box(
modifier = Modifier
.fillMaxWidth()
.weight(1f)
.background(Color.Gray)
) {
if (video) {
VideoContent(player)
} else {
ImageContent(stories, slide, progressBar)
}
}
}
}
}
@Composable
private fun VideoContent(player: ExoPlayer?) {
if (player == null) return
Box(modifier = Modifier.fillMaxSize()) {
ContentFrame(
player = player,
modifier = Modifier.fillMaxSize(),
surfaceType = SURFACE_TYPE_TEXTURE_VIEW,
contentScale = ContentScale.Fit
)
}
}
@Composable
private fun ImageContent(stories: String, slide: Int, progressBar: Dp) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.LightGray)
.offset(y = progressBar)
) {
Image(
painter = painterResource(R.drawable.ic_launcher_background),
contentDescription = null
)
Text(
text = "$stories, $slide",
modifier = Modifier.align(Alignment.Center)
)
}
}The result:
You can use either both or one of the components. In second case you need to synchronize stories shown indicator manually because they both use the same entry point to maintain the logic (the preview component observes which stories were shown in the container one). To do so you need to use the repository contract. Create the repo you can with the factory. The samples of synchronization are here and here. Keep in mind that the interaction is asynchronous so that it must be on worker thread otherwise an exception will be thrown.