Everyone Has a Story

Almost everyone has heard of the story feature. We were first introduced to this feature with Snapchat and many applications have added it ever since, the most prominent being Instagram, Facebook, and Whatsapp. What about you? Have you added it to your application? If not, let me show you how!

Structure

Before starting, we should talk about the structure of a story.
To navigate between stories, the user taps left or right. Stories can be stopped by long pressing. Once one user's story is over, we switch to another user. So how can we implement this in the simplest way? On first thought, we can do use a list and a videoPlayer. This may seem like a simple solution, but when multiple users and stories are involve, it makes management very difficult. Instead, we can use a fragment for each user, a videoPlayer for stories within the fragment and we can manage all the fragments with a ViewPager. Now that we’ve figured out the structure let’s start by downloading the project from that link.

When we download and start the project we'll see a screen like this:

Start Project

We see a list of stories ordered horizontally. Of course, when we click any one of them, nothing happens. We have not yet implemented the functionality. To start with, right click on ui package and create a new Kotlin class. Name it StoryAdapter. Copy the following code and paste it in this class.

In the above code, we created our adapter for viewPager. Now open up activity_story.xml and create ViewPager. Now we need a fragment to fill this viewPager. Let's create our fragment. Right click on ui package again and create an empty fragment and name it StoryFragment.Than go to fragment_story.xml and copy the following code and paste it in that layout.

To clarifyCircleImageView -> story owner's photo
PlayerView -> our video player
TextView -> story owner's username
ImageView -> cancel button for story screen
ProgressBar -> will appear until the story is ready

Pass Data

Now we will head over to MainActivity to pull the story list. When we click on a story, we want to see that specific and what follows. We don't need to see the previous ones. Therefore we have to discard them from our list. The following method does this.

And copy the following code and paste it in OnClickUser()

Here we pass our list to the StoryActivity but we forgot to do something. We didn't define the newInstance() method. Go to StoryActivity and paste the following code.

Now everything is ok. We passed our list to StoryActivity. Let's add the fragment to the viewPager. Also let’s handle the list that’s coming from MainActivity.

In the above code block, we created the adapter and binded the first fragment.Go to StoryFragment and create the newInstance() method.

Here we have to take only one user from our list for each fragment. Like I mentioned at the start, each user corresponds to just one fragment.

In code above we handle the user object and bind the photo with Glide and username.Now we are ready to watch our first story, but first we have to create the exoPlayer.

Prepare ExoPlayer

Firstly we need a media source for exoplayer with a videoList for multiple stories. For the media source we will use ConcatenatingMediaSource. The ConcatenatingMediaSource is now our video list. All stories will now be added to it.

In the above method, we created a videoList and added all the stories of a user. We created the media in this way because we took the stories from the raw folder. If our stories came from a url we would create media using another method. For detailed information ExoPlayer
Now let's initialize the exoPlayer.

1 - Initialize the exoPlayer
2 - Full screen
3 - When exoPlayer is ready it'll play automatically
4 - We created a media sourceMore information please visit ExoPlayer
It's not compiling now! We need to create the releasePlayer method to tidy up nicely.

And there is one last thing we need to do to watch our first story. Let's go back to StoryActivity and create onPageChangeListener.

In this code block, when activity is started, exoPlayer will play. Let's run project and click any story

As you can see when we clicked the story, we could see all the stories that belong to that user but we can't switch to another to user. Now we'll create an interface in StoryFragment. We'll be able to switch between stories and users by clicking on the right and left of the screen using that interface.

Switch Between Users

Go to fragment_story.xml layout and copy the following code and paste

Let's implement navigating between stories. The scenario is actually quite simple. If the user has a story, we will move on to the next story, otherwise we will move on to the next user.

Remember to call these methods in onActivityCreated.We'll define a variable and a setter method for this interface.

Go back to StoryActivity and override IStoryClickListener

This control was made so as not to create a new fragment each time. If we go to the previous user and want to go back to the next user, it wont add a new fragment to the viewPager. We update the viewpager’s current item with each click. If we reach the last user and that user’s last story, we kill the activity once the story finishes playing.Go to setupFragment method and update like so:

And update storyAdapter.addFragment method in onCreate:

Go back to storyFragment and paste this code. Here we'll release the player.

Let's run the project and see what happens.

Prepare Progress

Wait a minute, looks like something's wrong. All right we forgot to add a progress bar. We will be using Horizontal Progress for this purpose But we should note that the user may have either one story or more therefore we need a dynamic structure. We need a view to put the progress bar in. Copy and paste the following code above to the image view in fragment_story.xml.

Then go back StoryFragment and paste this code.

We created the progress bars in the code above, and we have set the max value and we have included it in the view we created. Then we added each of them to the list for the update process. Let's call this method in the prepareMediaSource method.

In order not to overlap, we gave weight to each progress bar. We need to remove the progress bar that remains when the user moves on to the next fragment.//code start//private fun removeProgress() {if (progressList.isNotEmpty()) {progressList.clear()llProgressContainer.removeAllViews()}} //code finish//Add the above method below releasePlayer() inside of setUserVisibleHint().Now run the project again.

Update Progress

As you can see the progress bar has the correct number of bars, but the bars do not show progress.

Here we will update the progression we created with the timer. So how will we know which progress bar to update? Using the current index of Exoplayer, we will pick the corresponding progress bar from the progress list. The length of the video is divided into 100ms partitions and this will be used to fill the progress bar. So where do we call this method? Exoplayer gives us a listener to listen to the current state of the media. Here we can find out which part of the story is playing.

*onTracksChanged()We are updating the progression when it passes to the next story.*onPlayerStateChanged()State.READY When the story is ready, we set our loading object visibility to gone, then we call our updateProgress() method.State.BufferingWe set our loading object visibility to visibleState.EndnextStory() will be called. And add this code below to exoplayer.prepare inside initializePlayer()

We don't want a nlp error. We have to release the timer. Add this code in removeProgress(), setupnextClick(), and setupPreviousClick()


And run the project again

Add this code to cancelImage in onActivityCreated()

via GIPHY

Conclusion

Congratulations, you can now track your stories from your application. There are missing sections, like moving between users and pausing a story by holding the screen.Maybe in the next article we will delve more into detail. See you in the next article.

References

https://developer.android.com/reference/androidx/viewpager/widget/ViewPager?hl=en
https://developer.android.com/guide/topics/media/exoplayer
https://google.github.io/ExoPlayer/guide.html
https://kotlinlang.org/docs/reference/extensions.html
https://kotlinlang.org/docs/tutorials/kotlin-for-py/objects-and-companion-objects.html
https://kotlinlang.org/docs/reference/properties.html#late-initialized-properties-and-variables
https://developer.android.com/reference/android/widget/ProgressBar
https://github.com/google/gson
https://github.com/bumptech/glide
https://github.com/hdodenhof/CircleImageView
https://developer.android.com/guide/topics/ui/layout/recyclerview
https://www.youtube.com/watch?v=LfeIfiiBTfY
https://www.youtube.com/watch?v=JX8tsfRwxa8
https://www.youtube.com/watch?v=FTpCr-H0srA
https://www.youtube.com/watch?v=2HF-yVuslS4
https://www.youtube.com/watch?v=oOLIEchkrAU
https://www.youtube.com/watch?v=kd7NFnexUm8
Contact: recep@duyuruapp.com