We’ll get into the card views in a bit, but in a nutshell:

Users can browse through the rows of content. When a card becomes focused, it will enlarge and the video for the Post will automatically start looping in the card view. Moving to another card will stop the video for the previous card and start the video for the current one.

When the user reaches the last item in the row, a paginated request for the next set of items will automatically be made. If items are returned then this will be added to the list and the ‘next page’ value is added to the adapter. If we reach the last page then this is flagged and a request will not be made when the user next reaches the last item in the row.

If there are no cards currently loaded and the request returns an error, then a “Try Again” card will be displayed so the user can re-attempt the request.

If there are already some cards loaded and the user makes a paginated request which returns an error, then the user will simply be shown a toast error message. The request will then be reattempted when the user focuses on the last item of the list again.

If there are no cards currently loaded and there are no results returned, then a “Check Again” card will be displayed so the user can make the request to check again.

Fragment Background

As the user navigates through the posts, we change the background of the fragment to a the thumbnail used for the focused Post. This helps to create a more dynamic experience and builds engagement. The Vine thumbnails aren’t the best quality, so it helps to have high quality images for this.

To do this, we use Glide to fetch the image and display it:

I wanted to be able to load small chunks of posts at a time, yet allow the user to load more if they reached the last item in the row - sounds like pagination to me! For this, I created the PaginationAdapter which handles several different aspects:

It holds the tag which we’re using in our query, the next page to be fetched from the server and the anchor string used in the paginated requests.

It uses a PresenterSelector to determine which item is to be displayed in the adapter. This allows us to display instance of Post Cards, Loading Cards and Icon Cards. It also contains methods to handle the display of these cards.

Having this custom adapter allows us to encapsulate the pagination data from outside of other classes and allows a lot of the logic to be reused for different adapter across the application.

Custom Views

Whilst the leanback library is great, it doesn’t provide a vast variety of card types for the display of content. In this case, the application uses several custom views that I created to enhance the user experience.

When a card view displaying a Post item becomes focused by the user when they’re browsing content, the card will automatically start looping the video as a preview for that Post.

When the video is no longer focused, we call the finish method for the view and the card is returned to its normal ImageView state. It adds a nice touch to the application and helps to make the user feel more engaged then only seeing static content - a mimic of real TV behaviour.

To begin with, I created a custom LoopingVideoView which extends VideoView to handle the looping and audio properties of the video — this view is then used in the custom PreviewCardView layout I created.

As seen in the layout file for this widget, we show a ProgressBar along with a transparent overlay on top of the ImageView whilst the video is being loaded. Once the VideoReady listener is called we remove this progress bar and overlay, this is when the video starts playing.

P.s. Thanks Ben Breckler and Matt Oakes for this suggestion!

When the PaginationAdapter is waiting for data, we want the user to be aware that something is happening in the background. For this reason, I decided to create a simple view that contains a ProgressBar inside of it.

Now, whenever network requests are taking place this view is shown to notify the user that content is being loaded.

To implement this, we use a simple layout alongside the LoadingCardView which handles the actual display of the card contents. The LoadingPresenter is used by the content adapters to handle the initialisation and display of the card itself.

The IconCardView was created so that I could display an Icon along with a Title/Value combination. Whilst the adapter for the rows in our content fragments will detect an Option model, the IconItemPresenter will handle the actual display of our Icon Cards.