StoryBlock (Android)

StoryBlock component allows the host app to embed the Fireworks video player directly into its view hierarchy.

Story block integrated into the layout

Lifecycle

Integration

To include a StoryBlock in your app, add it to your app's layout, and initialise it by calling init() method.

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="300dp"
            android:layout_height="400dp"
            android:layout_gravity="center"
            android:layout_marginVertical="16dp">

            <com.firework.storyblock.FwStoryBlockView
                android:id="@+id/story_block"
                android:layout_width="0dp"
                android:layout_height="0dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintDimensionRatio="9:16"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
        </androidx.constraintlayout.widget.ConstraintLayout>

Initialisation of the StoryBlock the component is as below

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val viewOptions = viewOptions {
            baseOptions {
                feedResource(FeedResource.Discovery)
            }
            playerOptions {
                playerMode(PlayerMode.FIT_MODE)
            }
            storyBlockOptions {
                enableAutoPlay(true)
                showFullScreenIcon(true)
            }
        }

        binding.storyBlock.init(
            fragmentManager = supportFragmentManager,
            lifecycle = lifecycle,
            viewOptions = viewOptions,
            pauseWhenNotVisible = true,
        )
    }
}

When you set the pauseWhenNotVisible parameter to true in the init() function, the StoryBlock will take automatic action to pause (or mute, in the case of a livestream) its playback whenever it becomes invisible on the screen. It will then resume normal playback when it becomes visible again.

Calling storyblock.destroy()releases all resources allocated for the StoryBlock.

StoryBlock standalone configurations

You can choose whether to enable autoplay mode or not; it's turned on by default.

You can also decide if you want to display the full-screen icon on the story block by adjusting the settings in storyBlockOptions; the default setting for this is true.

        val viewOptions = viewOptions {
            baseOptions {
                feedResource(FeedResource.Discovery)
            }
            playerOptions {
                playerMode(PlayerMode.FIT_MODE)
            }
            storyBlockOptions {
                enableAutoPlay(true)
                showFullScreenIcon(true)
            }
        }

        binding.storyBlock.init(
            fragmentManager = supportFragmentManager,
            lifecycle = lifecycle,
            viewOptions = viewOptions,
            pauseWhenNotVisible = true,
        )

StoryBlock player modes

You may choose between two-player modes for the StoryBlock:

  • FIT_MODE

  • FULL_BLEED_MODE

When StoryBlock is set up to display video in PlayerMode.FIT_MODE, internally it tries to scale video with 9:16 dimension ratio. To achieve the proper result StoryBlock the container should be placed into ConstraintLayout with app:layout_constraintDimensionRatio="9:16" attribute:

<androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="300dp"
            android:layout_gravity="center"
            android:layout_marginVertical="16dp">

          <com.firework.storyblock.FwStoryBlockView
                android:id="@+id/story_block"
                android:layout_width="0dp"
                android:layout_height="0dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintDimensionRatio="9:16" \\ this property is needed for FIT_MODE
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />   

 </androidx.constraintlayout.widget.ConstraintLayout>

If StoryBlock is set up with FULL_BLEED_MODE , it will just fill in the container following its width and height.

Fullscreen and Compact state

StoryBlock maybe displayed in fullscreen and compact mode

It is possible to open the fullscreen mode programmatically by calling:

storyBlock.openFullscreen()

Play and pause the video in StoryBlock

Users can pause and resume the video by calling the following functions

storyBlock.pause()
// and
storyBlock.play()

Keep in mind that pause() function will not work for livestreams.

Monitoring feed loading states and handling errors that occur during StoryBlock operation

The FwStoryBlockView class provides two key listener methods for monitoring feed loading states and handling errors that occur during StoryBlock operation.

setFeedLoadListener

fun setFeedLoadListener(feedLoadListener: FeedLoadListener?)

Description: Sets a listener to monitor the feed loading state of the StoryBlock. This listener provides real-time updates about the loading process, including when the feed is being loaded, when it has successfully loaded, or when it's empty.

Parameters:

  • feedLoadListener: An optional FeedLoadListener instance. Pass null to remove an existing listener.

Listener Interface:

fun interface FeedLoadListener {
    fun onFeedLoadStateChanged(feedLoadState: FeedLoadState)
}

Feed Load States:

  • FeedLoadState.Loading: The feed is currently being loaded from the server

  • FeedLoadState.FeedLoaded: The feed has been successfully loaded and is ready for display

  • FeedLoadState.EmptyFeed: The feed was loaded successfully but contains no content

  • FeedLoadState.EndOfFeed: The end of the feed has been reached

Usage Example:

storyBlockView.setFeedLoadListener { state ->
    when (state) {
        is FeedLoadState.Loading -> {
            // Show loading indicator
            showLoadingProgress()
        }
        is FeedLoadState.FeedLoaded -> {
            // Hide loading indicator and enable interactions
            hideLoadingProgress()
            enableUserInteractions()
        }
        is FeedLoadState.EmptyFeed -> {
            // Show empty feed message
            showEmptyFeedMessage()
        }
        is FeedLoadState.EndOfFeed -> {
            // Handle end of feed scenario
            showEndOfFeedMessage()
        }
    }
}

Best Practices:

  • Set the listener before calling init() to ensure you receive all state changes

  • Handle all possible FeedLoadState values in your implementation

  • Remove the listener by passing null when the StoryBlock is no longer needed

  • Use this listener to coordinate UI updates with the loading state

setOnErrorListener

fun setOnErrorListener(listener: FwErrorListener)

Description: Sets a listener to handle errors that occur during StoryBlock operation. This listener receives notifications about various types of errors, including SDK initialization errors, network issues, and StoryBlock-specific errors.

Parameters:

  • listener: A FwErrorListener instance that will receive error notifications

Listener Interface:

fun interface FwErrorListener {
    fun onFwError(error: FwError)
}

Error Types: The listener can receive various error types including:

  • SdkLevelError.SdkNotInitialized: The Firework SDK has not been initialized

  • StoryBlockError.InitializationFailed: StoryBlock initialization failed

  • StoryBlockError.DestructionFailed: StoryBlock destruction failed

  • NetworkError: Network-related errors during feed loading

  • PlayerError: Video playback errors

  • LivestreamError: Live streaming specific errors

Usage Example:

storyBlockView.setOnErrorListener { error ->
    when (error) {
        is SdkLevelError.SdkNotInitialized -> {
            // Handle SDK not initialized error
            showSdkInitializationError()
            initializeSdk()
        }
        is StoryBlockError.InitializationFailed -> {
            // Handle StoryBlock initialization failure
            showInitializationError(error.message)
        }
        is NetworkError -> {
            // Handle network-related errors
            showNetworkError()
            retryNetworkRequest()
        }
        is PlayerError -> {
            // Handle video playback errors
            showPlaybackError()
        }
        else -> {
            // Handle other error types
            showGenericError(error::class.java.simpleName)
        }
    }
    
    // Log the error for debugging
    Log.e("StoryBlock", "Error occurred: ${error::class.java.simpleName}")
}

Error Management:

  • The method automatically manages error listener registration and cleanup

  • When setting a new listener, any existing listener is automatically removed

  • The listener is automatically removed when the StoryBlock is destroyed

Removing Error Listener:

// To remove the error listener
storyBlockView.removeOnErrorListener(listener)

Integration Example

Here's a complete example showing both listeners working together:

class StoryBlockActivity : AppCompatActivity() {
    
    private lateinit var storyBlockView: FwStoryBlockView
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_story_block)
        
        storyBlockView = findViewById(R.id.storyBlockView)
        
        // Set up listeners before initialization
        setupListeners()
        
        // Initialize the StoryBlock
        initializeStoryBlock()
    }
    
    private fun setupListeners() {
        // Feed loading listener
        storyBlockView.setFeedLoadListener { state ->
            handleFeedLoadState(state)
        }
        
        // Error listener
        storyBlockView.setOnErrorListener { error ->
            handleError(error)
        }
    }
    
    private fun initializeStoryBlock() {
        val viewOptions = ViewOptions.Builder()
            .setFeedId("your-feed-id")
            .build()
            
        storyBlockView.init(
            fragmentManager = supportFragmentManager,
            lifecycleOwner = this,
            viewOptions = viewOptions
        )
    }
    
    private fun handleFeedLoadState(state: FeedLoadState) {
        when (state) {
            is FeedLoadState.Loading -> {
                binding.progressBar.visibility = View.VISIBLE
                binding.errorView.visibility = View.GONE
                binding.emptyView.visibility = View.GONE
            }
            is FeedLoadState.FeedLoaded -> {
                binding.progressBar.visibility = View.GONE
                // StoryBlock is ready for interaction
            }
            is FeedLoadState.EmptyFeed -> {
                binding.progressBar.visibility = View.GONE
                binding.emptyView.visibility = View.VISIBLE
            }
            is FeedLoadState.EndOfFeed -> {
                // Handle end of feed
            }
        }
    }
    
    private fun handleError(error: FwError) {
        binding.progressBar.visibility = View.GONE
        
        when (error) {
            is SdkLevelError.SdkNotInitialized -> {
                showError("SDK not initialized. Please initialize the SDK first.")
            }
            is NetworkError -> {
                showError("Network error. Please check your connection.")
            }
            else -> {
                showError("An error occurred: ${error::class.java.simpleName}")
            }
        }
    }
    
    override fun onDestroy() {
        super.onDestroy()
        // Clean up listeners
        storyBlockView.setFeedLoadListener(null)
        storyBlockView.removeOnErrorListener(errorListener)
        storyBlockView.destroy()
    }
}

Automatically release StoryBlock (Deprecated, please use FwStoryBlockView instead)

The FwLifecycleAwareStoryBlockView is a wrapper for the FwStoryBlockView class, providing automatic cleanup when the parent component (Fragment or Activity) is destroyed.

To utilize and set up the FwLifecycleAwareStoryBlockView, follow the same procedures as you would for the FwStoryBlockView. The only difference is that the destroy() method will be triggered automatically when needed.

Last updated

Was this helpful?