Skip to content

Commit 367864e

Browse files
Merge pull request #14 from reactivedroid/paging-3
Migration to Paging 3
2 parents cc52bc5 + 93ba4c3 commit 367864e

17 files changed

+379
-425
lines changed

app/src/main/java/com/android/tvmaze/network/TvMazeApi.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package com.android.tvmaze.network
22

3+
import androidx.paging.PagingData
34
import com.android.tvmaze.network.home.Episode
45
import com.android.tvmaze.network.home.Show
6+
import kotlinx.coroutines.flow.Flow
57
import retrofit2.http.GET
68
import retrofit2.http.Query
79

app/src/main/java/com/android/tvmaze/shows/AllShowsActivity.kt

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,74 +3,83 @@ package com.android.tvmaze.shows
33
import android.content.Context
44
import android.content.Intent
55
import android.os.Bundle
6+
import android.view.LayoutInflater
67
import android.view.MenuItem
7-
import android.view.View
88
import android.widget.Toast
99
import androidx.activity.viewModels
1010
import androidx.appcompat.app.AppCompatActivity
1111
import androidx.core.content.ContextCompat
12-
import androidx.lifecycle.Observer
13-
import androidx.paging.PagedList
14-
import androidx.recyclerview.widget.LinearLayoutManager
15-
import androidx.recyclerview.widget.RecyclerView
12+
import androidx.core.view.isVisible
13+
import androidx.lifecycle.lifecycleScope
14+
import androidx.paging.LoadState
1615
import com.android.tvmaze.R
17-
import com.android.tvmaze.network.home.Show
16+
import com.android.tvmaze.databinding.ActivityAllShowsBinding
1817
import dagger.hilt.android.AndroidEntryPoint
19-
import kotlinx.android.synthetic.main.activity_all_shows.*
20-
import kotlinx.android.synthetic.main.toolbar.view.*
18+
import kotlinx.coroutines.flow.collectLatest
19+
import kotlinx.coroutines.launch
2120

2221
@AndroidEntryPoint
23-
class AllShowsActivity : AppCompatActivity(), ShowsPagedAdaptor.Callback {
22+
class AllShowsActivity : AppCompatActivity() {
2423
private val showsViewModel: ShowsViewModel by viewModels()
25-
private lateinit var showsPagedAdaptor: ShowsPagedAdaptor
26-
24+
private lateinit var adapter: ShowsPagedAdapter
25+
private lateinit var showsBinding: ActivityAllShowsBinding
2726
override fun onCreate(savedInstanceState: Bundle?) {
2827
super.onCreate(savedInstanceState)
29-
setContentView(R.layout.activity_all_shows)
28+
showsBinding = ActivityAllShowsBinding.inflate(LayoutInflater.from(this))
29+
setContentView(showsBinding.root)
3030
setToolbar()
31-
showsViewModel.onScreenCreated()
3231
initAdapter()
33-
showsViewModel.initialLoadState().observe(this, Observer { setProgress(it) })
32+
getShows()
33+
showsBinding.retry.setOnClickListener { adapter.retry() }
3434
}
3535

36-
private fun initAdapter() {
37-
val layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
38-
showsPagedAdaptor = ShowsPagedAdaptor(ShowDiffUtilItemCallback(), this)
39-
shows.layoutManager = layoutManager
40-
shows.adapter = showsPagedAdaptor
41-
showsViewModel.getShows().observe(this, Observer { showAllShows(it) })
42-
showsViewModel.paginatedLoadState().observe(this, Observer { setAdapterState(it) })
36+
private fun getShows() {
37+
lifecycleScope.launch { showsViewModel.shows().collectLatest { adapter.submitData(it) } }
4338
}
4439

45-
private fun setAdapterState(networkState: NetworkState) {
46-
showsPagedAdaptor.setNetworkState(networkState)
40+
private fun initAdapter() {
41+
adapter = ShowsPagedAdapter(ShowDiffUtilItemCallback())
42+
showsBinding.shows.adapter = adapter.withLoadStateFooter(
43+
footer = ShowsLoadStateAdapter { adapter.retry() }
44+
)
45+
46+
adapter.addLoadStateListener { combinedLoadStates ->
47+
// Handle the initial load state
48+
when (val loadState = combinedLoadStates.source.refresh) {
49+
is LoadState.NotLoading -> {
50+
showsBinding.progress.isVisible = false
51+
showsBinding.shows.isVisible = true
52+
showsBinding.errorGroup.isVisible = false
53+
}
54+
is LoadState.Loading -> {
55+
showsBinding.progress.isVisible = true
56+
showsBinding.errorGroup.isVisible = false
57+
}
58+
is LoadState.Error -> {
59+
showsBinding.progress.isVisible = false
60+
showsBinding.errorGroup.isVisible = true
61+
showsBinding.errorMsg.text = loadState.error.localizedMessage
62+
}
63+
}
64+
65+
// Show message to the user when an error comes while loading the next page
66+
val errorState = combinedLoadStates.source.append as? LoadState.Error
67+
?: combinedLoadStates.append as? LoadState.Error
68+
errorState?.let {
69+
Toast.makeText(this, errorState.error.localizedMessage, Toast.LENGTH_SHORT).show()
70+
}
71+
}
4772
}
4873

4974
private fun setToolbar() {
50-
val toolbar = toolbar.toolbar
75+
val toolbar = showsBinding.toolbar.toolbar
5176
setSupportActionBar(toolbar)
5277
toolbar.setTitleTextColor(ContextCompat.getColor(this, android.R.color.white))
5378
toolbar.setSubtitleTextColor(ContextCompat.getColor(this, android.R.color.white))
5479
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
5580
setTitle(R.string.shows)
5681
}
5782

58-
private fun setProgress(loadState: NetworkState) {
59-
when (loadState) {
60-
is Success -> progress.visibility = View.GONE
61-
is NetworkError -> {
62-
progress.visibility = View.GONE
63-
Toast.makeText(this, loadState.message, Toast.LENGTH_SHORT).show()
64-
}
65-
is Loading -> progress.visibility = View.VISIBLE
66-
}
67-
}
68-
69-
private fun showAllShows(showsList: PagedList<Show>) {
70-
showsPagedAdaptor.submitList(showsList)
71-
shows.visibility = View.VISIBLE
72-
}
73-
7483
override fun onOptionsItemSelected(item: MenuItem): Boolean {
7584
return if (item.itemId == android.R.id.home) {
7685
finish()
@@ -80,10 +89,6 @@ class AllShowsActivity : AppCompatActivity(), ShowsPagedAdaptor.Callback {
8089
}
8190
}
8291

83-
override fun onRetryClicked() {
84-
showsViewModel.retry()
85-
}
86-
8792
companion object {
8893
fun start(context: Context) {
8994
val starter = Intent(context, AllShowsActivity::class.java)

app/src/main/java/com/android/tvmaze/shows/NetworkState.kt

Lines changed: 0 additions & 6 deletions
This file was deleted.

app/src/main/java/com/android/tvmaze/shows/ShowsDataSource.kt

Lines changed: 0 additions & 111 deletions
This file was deleted.

app/src/main/java/com/android/tvmaze/shows/ShowsDataSourceFactory.kt

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.android.tvmaze.shows
2+
3+
import android.view.ViewGroup
4+
import androidx.paging.LoadState
5+
import androidx.paging.LoadStateAdapter
6+
7+
class ShowsLoadStateAdapter(private val retry: () -> Unit) :
8+
LoadStateAdapter<ShowsStateViewHolder>() {
9+
override fun onBindViewHolder(holder: ShowsStateViewHolder, loadState: LoadState) {
10+
holder.bind(loadState)
11+
}
12+
13+
override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): ShowsStateViewHolder {
14+
return ShowsStateViewHolder.create(parent, retry)
15+
}
16+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package com.android.tvmaze.shows
2+
3+
import android.content.Context
4+
import android.view.LayoutInflater
5+
import android.view.ViewGroup
6+
import androidx.paging.PagingDataAdapter
7+
import androidx.recyclerview.widget.DiffUtil
8+
import androidx.recyclerview.widget.RecyclerView
9+
import com.android.tvmaze.R
10+
import com.android.tvmaze.databinding.AllShowListItemBinding
11+
import com.android.tvmaze.network.home.Show
12+
import com.bumptech.glide.Glide
13+
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
14+
import com.bumptech.glide.request.RequestOptions
15+
16+
class ShowsPagedAdapter constructor(
17+
diffCallback: DiffUtil.ItemCallback<Show>
18+
) : PagingDataAdapter<Show, RecyclerView.ViewHolder>(diffCallback) {
19+
private lateinit var context: Context
20+
21+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
22+
context = parent.context
23+
val layoutInflater = LayoutInflater.from(context)
24+
val showListItemBinding = AllShowListItemBinding.inflate(layoutInflater, parent, false)
25+
return ShowHolder(showListItemBinding)
26+
}
27+
28+
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
29+
if (holder is ShowHolder) {
30+
val show = getItem(position)
31+
holder.binding.show = show
32+
if (show!!.rating != null) {
33+
holder.binding.rating = show.rating!!["average"]
34+
}
35+
configureImage(holder, show)
36+
}
37+
}
38+
39+
private fun configureImage(holder: ShowHolder, show: Show) {
40+
if (show.image != null) {
41+
Glide.with(context).load(show.image["original"])
42+
.apply(RequestOptions.placeholderOf(R.color.grey))
43+
.centerCrop()
44+
.transition(DrawableTransitionOptions.withCrossFade())
45+
.into(holder.binding.showImage)
46+
}
47+
}
48+
49+
class ShowHolder(val binding: AllShowListItemBinding) : RecyclerView.ViewHolder(binding.root)
50+
}

0 commit comments

Comments
 (0)