> For the complete documentation index, see [llms.txt](https://docs.firework.com/firework-for-developers/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.firework.com/firework-for-developers/android-sdk/integration-guide/compose-support-android.md).

# Compose Support

Before integrating the **VideoFeed** and **StoryBlock** components in your Android Compose project, **make sure to follow the official** [**Firework Getting Started Guide for Android SDK**](https://docs.firework.com/firework-for-developers/android-sdk/integration-guide/getting-started).

## Video Feed

An Activity that uses the **VideoFeed** component must extend `ComponentActivity` or a subclass of `ComponentActivity`.

A Fragment that uses the **VideoFeed** component must extend `Fragment` or a subclass of `Fragment`.

Then you can add VideoFeed to your project

```kotlin
@Composable
private fun VideoFeed(modifier: Modifier) {
    AndroidView(
        modifier = modifier.fillMaxSize(),
        factory = { context ->
            fwVideoFeedView(context) {
                // Recommended: register listeners BEFORE viewOptions { } — it calls
                // init() internally, so a listener added after it may miss the
                // first-page onFeedLoad callback.
                setOnFeedLoadListener { videos ->
                    videos.forEach { Log.d("VideoFeed", "loaded ${it.id}, feedId=${it.feedId}") }
                }
                viewOptions {
                    // ...
                }
            }
        },
        onRelease = { it.destroy() },
    )
}
```

> **Recommended:** In the DSL form, `viewOptions { }` triggers `init()`. Register `setOnFeedLoadListener` (and other listeners) **before** `viewOptions { }` to reliably receive the **first-page** callback.

For viewOptions detail configuration, refer to the [video-feed-integration](https://docs.firework.com/firework-for-developers/android-sdk/integration-guide/video-feed/configure-video-feed#video-feed-integration) doc, you are allowed to fill in more options here.

## Storyblock

An Activity that uses the **Storyblock** component must extend `FragmentActivity` or a subclass of `FragmentActivity`.

A Fragment that uses the **Storyblock** component must extend `Fragment` or a subclass of `Fragment.`

### Use single storyblock

Create a Storyblock code down below, and add the widget to your compose code.

```
@Composable
fun StoryblockItem(modifier: Modifier = Modifier) {
    val context = LocalContext.current
    // create a FwStoryBlockView
    val storyBlockView = FwStoryBlockView(context)
    // init view options
    val viewOptions = viewOptions {
        baseOptions {
            feedResource(FeedResource.Discovery)
        }
        playerOptions {
            playerMode(PlayerMode.FIT_MODE)
        }
        storyBlockOptions {
            enableAutoPlay(true)
            showFullScreenIcon(true)
        }
    }

    AndroidView(
        modifier = modifier.padding(start = 20.dp, top = 50.dp, end = 20.dp, bottom = 50.dp),
        factory = { _ ->
            // initial storyblock
            storyBlockView.init( 
                // if you are using fragment as container, replace it with childFragmentManager
                (context as FragmentActivity).supportFragmentManager, 
                context,
                viewOptions,
                true
            )
            storyBlockView.apply {
                // set layout parameters 
                layoutParams = ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT
                )
                setOnErrorListener { e ->
                    // handle and record the error
                }
                
                // set other listeners
                ......
            }
        }
    )
    
    DisposableEffect(Unit) {
        onDispose {
            // invoke destroy when disposable
            storyBlockView.destroy() 
        }
    }
}
```

To view the configuration details of the viewOptions, refer to the [Storyblock](https://docs.firework.com/firework-for-developers/android-sdk/integration-guide/storyblock) doc, you are allowed to fill in more options here.

**Note**

Don't forget to destroy the `FwStoryBlockView` in `DisposableEffect`

### Use multiple storyblocks in Grid

Create and Initialize the `FwStoryBlockView` with view options.

```
@Composable
fun StoryBlockItem(modifier: Modifier = Modifier, key: String, androidViewMap: MutableMap<String, FwStoryBlockView>) {
    val context = LocalContext.current
    val storyblockAndroidView = androidViewMap.getOrPut(key) {
        val storyBlockView = FwStoryBlockView(context = LocalContext.current)
        // init view options
        val viewOptions = viewOptions {
            baseOptions {
                feedResource(FeedResource.Discovery)
            }
            playerOptions {
                playerMode(PlayerMode.FIT_MODE)
            }
            storyBlockOptions {
                enableAutoPlay(true)
                showFullScreenIcon(true)
            }
        }
        storyBlockView.init(
            (context as AppCompatActivity).supportFragmentManager,
            context,
            viewOptions,
            true,
        )
        storyBlockView.apply {
            layoutParams = ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT,
            )
            storyBlockView.setOnErrorListener { e ->
                // handle the error
            }
        }
    }

    AndroidView(
        modifier = modifier
            .padding(top = 16.dp)
            .size(width, height),
        factory = { _ ->
            storyblockAndroidView
        },
        ...... 
    )
}
```

#### Integrate with LazyVerticalGrid Component

Build LazyVerticalGridItem demo code.

```
@Suppress("MagicNumber")
val list = List(50) {
    if (it == 3 || it == 24) {
        "View"
    } else {
        "Text"
    }
}

private val width = 150.dp
private val height = 250.dp

@Composable
fun LazyVerticalGridItem(modifier: Modifier = Modifier) {
    val androidViewMap = remember { mutableMapOf<String, FwStoryBlockView>() }
    LazyVerticalGrid(columns = GridCells.Fixed(2)) {
        items(list.size) { index ->
            if (list[index] == "View") {
                StoryBlockItem(modifier = modifier, key = "View_${index}", androidViewMap = androidViewMap)
            } else {
                Text(text = "Text $index", modifier = modifier.size(width, height))
            }
        }
    }

    DisposableEffect(Unit) {
        onDispose {
            // destroy all the cached storyblock view
            for (v in androidViewMap.values) {
                v.destroy()
            }
        }
    }
}
```

You can integrate `LazyVerticalGridItem` into your compose code.

**Note**

Don't forget to destroy the `FwStoryBlockView` in `DisposableEffect`
