# Widget - Video Feed View

`FwVideoFeedView` is a custom view that displays video thumbnails in a scrollable feed. Users can tap on any thumbnail to launch the fullscreen video player. The feed supports multiple layout types (horizontal, vertical, grid) and can display content from various sources.

## Integration

### Add to Layout

Add `FwVideoFeedView` to your layout XML file:

```xml
<com.firework.videofeed.FwVideoFeedView
    android:id="@+id/videoFeedView"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
```

### Initialize

Initialize the feed view by calling `init()`:

```kotlin
class MainActivity : AppCompatActivity() {
    private lateinit var videoFeedView: FwVideoFeedView
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        videoFeedView = findViewById(R.id.videoFeedView)
        
        // Simple initialization with defaults
        videoFeedView.init()
    }
    
    override fun onDestroy() {
        videoFeedView.destroy()
        super.onDestroy()
    }
}
```

### Initialize with ViewOptions

Provide `ViewOptions` to customize the feed:

```kotlin
val viewOptions = viewOptions {
    baseOptions {
        feedResource(FeedResource.Discovery)
    }
    layoutOptions {
        feedLayout(FeedLayout.GRID)
        columnCount(3)
        itemSpacing(8.dpToPx())
    }
}

videoFeedView.init(viewOptions)
```

## Configuration Options

### Feed Source (BaseOption)

Configure the content source for the feed. See [Feed Sources](/firework-for-developers/android-sdk/integration-guide/feed-sources.md) for detailed information on each type.

```kotlin
viewOptions {
    baseOptions {
        // Discovery feed
        feedResource(FeedResource.Discovery)
        
        // Or Channel feed
        feedResource(FeedResource.Channel(channelId = "your_encoded_channel_id"))
        
        // Or Playlist feed
        feedResource(
            FeedResource.Playlist(
                channelId = "your_encoded_channel_id",
                playlistId = "your_encoded_playlist_id"
            )
        )
        
        // Or Single content
        feedResource(FeedResource.SingleContent(contentId = "your_encoded_content_id"))
        
        // Or SKU-based feed
        feedResource(
            FeedResource.Sku(
                channelId = "your_encoded_channel_id",
                productIds = listOf("sku1", "sku2")
            )
        )
    }
}
```

For more feed types (HashtagPlaylist, DynamicContent, ShareUrl), see [BaseOption Configuration](/firework-for-developers/android-sdk/integration-guide/configuration/base-options.md).

### Layout Configuration (LayoutOption)

Control the visual layout and appearance of the video feed.

#### Feed Layout Types

```kotlin
viewOptions {
    layoutOptions {
        // Horizontal scrolling row (default)
        feedLayout(FeedLayout.HORIZONTAL)
        
        // Or vertical scrolling column
        feedLayout(FeedLayout.VERTICAL)
        
        // Or multi-column grid
        feedLayout(FeedLayout.GRID)
        columnCount(3) // Only for grid layout
    }
}
```

#### Spacing and Appearance

```kotlin
viewOptions {
    layoutOptions {
        // Item spacing
        itemSpacing(12.dpToPx()) // Space between items
        
        // Background color
        backgroundColor(Color.parseColor("#F5F5F5"))
        
        // Rounded corners
        roundedCorner(true)
        roundedCornerRadius(12.dpToPx())
        
        // Play icon
        showPlayIcon(true)
        playIconWidth(32.dpToPx())
        
        // Aspect ratio
        aspectRatio(9.0 / 16.0) // 9:16 ratio
    }
}
```

#### Title Position

```kotlin
viewOptions {
    layoutOptions {
        // Title overlays thumbnail (default)
        feedTitlePosition(FeedTitlePosition.NESTED)
        
        // Or title appears below thumbnail
        feedTitlePosition(FeedTitlePosition.STACKED)
    }
}
```

For complete layout options, see [LayoutOption Configuration](/firework-for-developers/android-sdk/integration-guide/configuration/layout-options.md).

### Title Configuration (TitleOption)

Customize the appearance of feed titles.

```kotlin
viewOptions {
    titleOptions {
        // Visibility
        showFeedTitle(true)
        
        // Text styling
        feedTitleTextColor(Color.WHITE)
        feedTitleTextSize(18.spToPx())
        feedTitleTextNumberOfLines(2)
        feedTitleTextPadding(12.dpToPx())
        
        // Background
        feedTitleBackgroundColor(Color.parseColor("#80000000"))
        
        // Custom font
        feedTitleTextTypeface(
            ResourcesCompat.getFont(context, R.font.custom_font)
        )
    }
}
```

#### Gradient Background

```kotlin
viewOptions {
    titleOptions {
        feedTitleBackgroundDrawable(
            GradientDrawable().apply {
                colors = intArrayOf(
                    Color.parseColor("#667eea"),
                    Color.parseColor("#764ba2")
                )
                gradientType = GradientDrawable.LINEAR_GRADIENT
                orientation = GradientDrawable.Orientation.TOP_BOTTOM
            }
        )
    }
}
```

For complete title options, see [TitleOption Configuration](/firework-for-developers/android-sdk/integration-guide/configuration/title-options.md).

### Player Configuration (PlayerOption)

Configure the fullscreen video player that opens when users tap on video thumbnails.

```kotlin
viewOptions {
    playerOptions {
        // Autoplay first visible video in feed
        autoplay(true)
        
        // Player display mode
        playerMode(PlayerMode.FIT_MODE) // or FULL_BLEED_MODE
        
        // Auto-play next video when current ends
        autoPlayOnComplete(true)
        
        // UI elements
        showShareButton(true)
        showMuteButton(true)
        showFireworkLogo(false)
        
        // Picture-in-Picture
        enablePipMode(true)
    }
}
```

For complete player configuration options, see [Video Player Configuration](/firework-for-developers/android-sdk/integration-guide/video-player.md).

### CTA Configuration (CtaOption)

Configure Call-to-Action button behavior.

```kotlin
viewOptions {
    ctaOptions {
        // CTA visibility delay
        ctaDelay(CtaDelay(3.0f, CtaDelayUnit.SECONDS))
        // Or use percentage
        ctaDelay(CtaDelay(0.5f, CtaDelayUnit.PERCENTAGE))
        
        // CTA highlight delay
        ctaHighlightDelay(CtaDelay(2.0f, CtaDelayUnit.SECONDS))
    }
}
```

**Delay Units:**

* `CtaDelayUnit.SECONDS` - Delay in seconds (0.0 - 10.0, default: 3)
* `CtaDelayUnit.PERCENTAGE` - Percentage of video duration (0.0 - 1.0, default: 0.2)

For CTA handling, see [Shopping Integration](/firework-for-developers/android-sdk/integration-guide/shoppable-videos.md).

### Ad Badge Configuration (AdBadgeOption)

Customize the ad badge appearance on sponsored content.

```kotlin
viewOptions {
    adBadgeOptions {
        // Visibility
        adBadgeIsHidden(false)
        adBadgeShowOnThumbnails(true)
        
        // Appearance
        adBadgeBackColor(Color.parseColor("#FFFECD"))
        adBadgeTextColor(Color.BLACK)
        
        // Label text
        adBadgeLabel(AdBadgeTextType.SPONSORED) // or AdBadgeTextType.AD
        
        // Custom font
        adBadgeTypeface(ResourcesCompat.getFont(context, R.font.custom_font))
    }
}
```

### Chat Configuration (ChatOption)

Configure livestream chat appearance.

```kotlin
viewOptions {
    chatOptions {
        // Chat text color
        chatTextColor(Color.WHITE)
        
        // Chat text shadow
        chatTextShadowColor(Color.BLACK)
        chatTextShadowOffsetX(2f)
        chatTextShadowOffsetY(2f)
        chatTextShadowRadius(4f)
    }
}
```

## Feed Refresh

Manually refresh the feed to reload content:

```kotlin
videoFeedView.refresh()
```

Example with SwipeRefreshLayout:

```kotlin
swipeRefreshLayout.setOnRefreshListener {
    videoFeedView.refresh()
    swipeRefreshLayout.isRefreshing = false
}
```

## Feed State Monitoring

### Feed View State Listener

Monitor feed loading states and respond to state changes:

```kotlin
videoFeedView.setOnFeedViewStateListener { feedViewState ->
    when (feedViewState) {
        is FeedViewState.Loading -> {
            // The feed is currently loading content
         
        }
        is FeedViewState.LoadData -> {
            // Data has been successfully loaded and is available
        }
        is FeedViewState.EmptyFeed -> {
            // The feed has no content to display
        }
        is FeedViewState.EndOfFeed -> {
            // User has reached the end of available content
        }
        is FeedViewState.Error -> {
            // An error occurred while loading feed content
        }
    }
}
```

**Feed View States:**

* `Loading` - Feed is currently loading content
* `LoadData` - Data has been successfully loaded
* `EmptyFeed` - Feed has no content to display
* `EndOfFeed` - End of available content reached
* `Error` - Error occurred with message

### Error Listener

Handle errors during feed operations:

```kotlin
videoFeedView.setOnErrorListener { error ->
    when (error) {
        is SdkLevelError.SdkNotInitialized -> {
            // SDK not initialized
            showError("Please initialize Firework SDK first")
        }
        is VideoFeedError.LoadingFailed -> {
            // Feed loading failed
            showError("Failed to load video feed")
        }
        is NetworkError -> {
            // Network error
            showError("Network error. Please check your connection")
        }
        is AdsError -> {
            // Ad-related error
            Log.e("VideoFeed", "Ad error: ${error::class.simpleName}")
        }
        is LivestreamError -> {
            // Livestream error
            Log.e("VideoFeed", "Livestream error: ${error::class.simpleName}")
        }
        else -> {
            showError("An error occurred: ${error::class.simpleName}")
        }
    }
}
```

**Error Types:**

* `SdkLevelError.SdkNotInitialized` - SDK not initialized
* `VideoFeedError.LoadingFailed` - Feed loading failed
* `AdsError` - Ad-related errors (VideoLoadFailed, PlaybackFailed, ImaAdFailed)
* `LivestreamError` - Livestream errors (MissingLivestreamInitializer, EngineFailed)
* `ShareContentError` - Share errors (EmptyShareUrl, SharingFailed)
* `NetworkError` - Network-related errors
* `PlayerError` - Video playback errors

### Feed Item Click Listener

#### setOnClickFeedItemListener (Recommended)

Register a click listener that supports **interception**. If the listener returns `true`, the SDK will **not** open the fullscreen player (the click is intercepted). If it returns `false`, the SDK handles the click normally.

```kotlin
videoFeedView.setOnClickFeedItemListener { index, videoInfo ->
    Log.d("VideoFeed", "Video clicked at index $index: ${videoInfo.videoId}")

    // Return true to intercept (prevent the SDK from opening the player)
    // Return false to let the SDK handle the click normally
    false
}
```

**Parameters:**

| Parameter   | Type        | Description                              |
| ----------- | ----------- | ---------------------------------------- |
| `index`     | `Int`       | Position of the clicked item in the feed |
| `videoInfo` | `VideoInfo` | Detailed video metadata                  |

**Return value:** `Boolean` — `true` to intercept, `false` to allow the SDK to open the player.

**Example: Intercept click to open a custom player**

```kotlin
videoFeedView.setOnClickFeedItemListener { index, videoInfo ->
    // Open your own player UI
    startActivity(MyCustomPlayerActivity.intent(this, videoInfo.videoId))
    true // Intercept — SDK will NOT open its player
}
```

#### setOnFeedItemClickListener (Deprecated)

> **Deprecated:** Use `setOnClickFeedItemListener` instead. This listener does not support click interception.

Track when users tap on feed items:

```kotlin
videoFeedView.setOnFeedItemClickListener { feedItem ->
    Log.d("VideoFeed", "Video clicked: ${feedItem.title}")

    val videoId = feedItem.id
    val title = feedItem.title
    val index = feedItem.indexInTheList
    val duration = feedItem.duration
    val videoInfo = feedItem.videoInfo
}
```

**FeedItem Properties:**

* `id` - Video content ID
* `title` - Video title
* `indexInTheList` - Position in feed
* `duration` - Video duration in milliseconds
* `videoInfo` - Detailed video information

## Lifecycle Management

### Destroy in Activity

Call `destroy()` when the feed view is no longer needed:

```kotlin
class VideoFeedActivity : AppCompatActivity() {
    private lateinit var videoFeedView: FwVideoFeedView
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_video_feed)
        
        videoFeedView = findViewById(R.id.videoFeedView)
        videoFeedView.init()
    }
    
    override fun onDestroy() {
        videoFeedView.destroy()
        super.onDestroy()
    }
}
```

### Destroy in Fragment

In fragments, call `destroy()` in `onDestroyView()`:

```kotlin
class VideoFeedFragment : Fragment() {
    private var _binding: FragmentVideoFeedBinding? = null
    private val binding get() = _binding!!
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        _binding = FragmentVideoFeedBinding.bind(view)
        
        binding.videoFeedView.init()
    }
    
    override fun onDestroyView() {
        binding.videoFeedView.destroy()
        super.onDestroyView()
        _binding = null
    }
}
```

## Complete Configuration Examples

### Grid Layout Feed

```kotlin
class GridFeedActivity : AppCompatActivity() {
    private lateinit var videoFeedView: FwVideoFeedView
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_grid_feed)
        
        videoFeedView = findViewById(R.id.videoFeedView)
        
        val viewOptions = viewOptions {
            baseOptions {
                feedResource(FeedResource.Discovery)
            }
            layoutOptions {
                feedLayout(FeedLayout.GRID)
                columnCount(3)
                itemSpacing(8.dpToPx())
                roundedCorner(true)
                roundedCornerRadius(12.dpToPx())
                backgroundColor(Color.parseColor("#F8F9FA"))
                showPlayIcon(true)
            }
            titleOptions {
                showFeedTitle(true)
                feedTitleTextColor(Color.WHITE)
                feedTitleBackgroundColor(Color.parseColor("#80000000"))
                feedTitleTextSize(14.spToPx())
                feedTitleTextNumberOfLines(2)
            }
            playerOptions {
                autoplay(false)
                showShareButton(true)
                enablePipMode(true)
            }
        }
        
        videoFeedView.init(viewOptions)
    }
    
    override fun onDestroy() {
        videoFeedView.destroy()
        super.onDestroy()
    }
}
```

### Horizontal Story Feed

```kotlin
class StoryFeedActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_story_feed)
        
        val videoFeedView = findViewById<FwVideoFeedView>(R.id.videoFeedView)
        
        val viewOptions = viewOptions {
            baseOptions {
                feedResource(FeedResource.Channel(channelId = "your_channel_id"))
            }
            layoutOptions {
                feedLayout(FeedLayout.HORIZONTAL)
                itemSpacing(16.dpToPx())
                roundedCorner(true)
                roundedCornerRadius(12.dpToPx())
                showPlayIcon(false) // No play icon for story style
                aspectRatio(9.0 / 16.0)
            }
            titleOptions {
                showFeedTitle(false)
            }
            playerOptions {
                autoplay(false)
                scrollingOrientation(ScrollingOrientation.VERTICAL)
            }
        }
        
        videoFeedView.init(viewOptions)
    }
}
```

### Product Video Gallery

```kotlin
class ProductGalleryActivity : AppCompatActivity() {
    private fun loadProductVideos(productSku: String) {
        val videoFeedView = findViewById<FwVideoFeedView>(R.id.productVideos)
        
        // Set up error listener
        videoFeedView.setOnErrorListener { error ->
            Toast.makeText(this, "Error: ${error::class.simpleName}", Toast.LENGTH_SHORT).show()
        }
        
        // Set up state listener
        videoFeedView.setOnFeedViewStateListener { state ->
            when (state) {
                is FeedViewState.Loading -> {
                    progressBar.isVisible = true
                }
                is FeedViewState.LoadData -> {
                    progressBar.isVisible = false
                }
                is FeedViewState.EmptyFeed -> {
                    progressBar.isVisible = false
                    emptyView.isVisible = true
                }
                else -> {}
            }
        }
        
        val viewOptions = viewOptions {
            baseOptions {
                feedResource(
                    FeedResource.Sku(
                        channelId = "your_channel_id",
                        productIds = listOf(productSku)
                    )
                )
            }
            layoutOptions {
                feedLayout(FeedLayout.GRID)
                columnCount(2)
                itemSpacing(8.dpToPx())
                roundedCorner(true)
                showPlayIcon(true)
            }
            playerOptions {
                autoplay(false)
                showShareButton(true)
            }
        }
        
        videoFeedView.init(viewOptions)
    }
}
```

## Important Notes

* Always call `init()` before the feed view can display content
* The SDK must be initialized (via `FireworkSdk.init()`) before calling `init()` on the feed view
* Always call `destroy()` when the feed view is no longer needed to free resources
* ViewOptions provided to `init()` allow complete customization of the feed
* For grid layout, `columnCount` determines the number of columns
* Autoplay on thumbnails can impact battery and data usage
* Use `dpToPx()` for density-independent pixel values
* Use `spToPx()` for text size values

## See Also

* [Feed Sources](/firework-for-developers/android-sdk/integration-guide/feed-sources.md) - Learn about different content sources
* [ViewOptions Configuration](/firework-for-developers/android-sdk/integration-guide/configuration.md) - Complete configuration system
* [BaseOption](/firework-for-developers/android-sdk/integration-guide/configuration/base-options.md) - Feed source configuration
* [LayoutOption](/firework-for-developers/android-sdk/integration-guide/configuration/layout-options.md) - Detailed layout customization
* [TitleOption](/firework-for-developers/android-sdk/integration-guide/configuration/title-options.md) - Title styling options
* [Video Player Configuration](/firework-for-developers/android-sdk/integration-guide/video-player.md) - Player configuration and features
* [Shopping Integration](/firework-for-developers/android-sdk/integration-guide/shoppable-videos.md) - CTA and shopping features
* [Widgets Overview](/firework-for-developers/android-sdk/integration-guide/widgets.md) - All available widgets


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.firework.com/firework-for-developers/android-sdk/integration-guide/configure-video-feed.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
