Refactor initAdapter

This commit is contained in:
mjaillot 2021-03-19 17:28:13 +01:00
parent d13b34ed0d
commit c2dd66c54f
6 changed files with 43 additions and 79 deletions

View File

@ -2,25 +2,32 @@ package com.h.pixeldroid.posts.feeds
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ProgressBar
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.core.view.isVisible
import androidx.core.view.size
import androidx.paging.LoadState
import androidx.paging.LoadStateAdapter
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.h.pixeldroid.R
import com.h.pixeldroid.databinding.FragmentFeedBinding
import com.h.pixeldroid.databinding.ErrorLayoutBinding
import com.h.pixeldroid.databinding.LoadStateFooterViewItemBinding
/**
* Shows or hides the error in the different FeedFragments
*/
private fun showError(errorText: String, show: Boolean = true, binding: FragmentFeedBinding){
if(show){
binding.motionLayout.transitionToEnd()
binding.errorLayout.errorText.text = errorText
} else if(binding.motionLayout.progress == 1F){
binding.motionLayout.transitionToStart()
private fun showError(
errorText: String, show: Boolean = true,
motionLayout: MotionLayout,
errorLayout: ErrorLayoutBinding){
if(show) {
motionLayout.transitionToEnd()
errorLayout.errorText.text = errorText
} else if(motionLayout.progress == 1F) {
motionLayout.transitionToStart()
}
}
@ -29,28 +36,32 @@ private fun showError(errorText: String, show: Boolean = true, binding: Fragment
*
* Makes the UI respond to various [LoadState]s, including errors when an error message is shown.
*/
internal fun <T: Any> initAdapter(binding: FragmentFeedBinding, adapter: PagingDataAdapter<T, RecyclerView.ViewHolder>) {
binding.list.adapter = adapter.withLoadStateFooter(
internal fun <T: Any> initAdapter(
progressBar: ProgressBar, swipeRefreshLayout: SwipeRefreshLayout,
recyclerView: RecyclerView, motionLayout: MotionLayout, errorLayout: ErrorLayoutBinding,
adapter: PagingDataAdapter<T, RecyclerView.ViewHolder>) {
recyclerView.adapter = adapter.withLoadStateFooter(
footer = ReposLoadStateAdapter { adapter.retry() }
)
adapter.addLoadStateListener { loadState ->
if(!binding.progressBar.isVisible && binding.swipeRefreshLayout.isRefreshing) {
if(!progressBar.isVisible && swipeRefreshLayout.isRefreshing) {
// Stop loading spinner when loading is done
binding.swipeRefreshLayout.isRefreshing = loadState.refresh is LoadState.Loading
swipeRefreshLayout.isRefreshing = loadState.refresh is LoadState.Loading
} else {
// ProgressBar should stop showing as soon as the source stops loading ("source"
// meaning the database, so don't wait on the network)
val sourceLoading = loadState.source.refresh is LoadState.Loading
if(!sourceLoading && binding.list.size > 0){
binding.list.isVisible = true
binding.progressBar.isVisible = false
} else if(binding.list.size == 0
if(!sourceLoading && recyclerView.size > 0){
recyclerView.isVisible = true
progressBar.isVisible = false
} else if(recyclerView.size == 0
&& loadState.append is LoadState.NotLoading
&& loadState.append.endOfPaginationReached){
binding.progressBar.isVisible = false
showError(binding = binding, errorText = "Nothing to see here :(")
progressBar.isVisible = false
showError(motionLayout = motionLayout, errorLayout = errorLayout, errorText = "Nothing to see here :(")
}
}
@ -63,13 +74,15 @@ internal fun <T: Any> initAdapter(binding: FragmentFeedBinding, adapter: PagingD
?: loadState.prepend as? LoadState.Error
?: loadState.refresh as? LoadState.Error
errorState?.let {
showError(binding = binding, errorText = it.error.toString())
showError(motionLayout = motionLayout, errorLayout = errorLayout, errorText = it.error.toString())
}
if(errorState == null) {
showError(motionLayout = motionLayout, errorLayout = errorLayout, show = false, errorText = "")
}
if (errorState == null) showError(binding = binding, show = false, errorText = "")
}
}
/**
* Adapter to the show the a [RecyclerView] item for a [LoadState], with a callback to retry if
* the retry button is pressed.

View File

@ -70,7 +70,8 @@ open class CachedFeedFragment<T: FeedContentDatabase> : BaseFragment() {
binding = FragmentFeedBinding.inflate(layoutInflater)
initAdapter(binding, adapter)
initAdapter(binding.progressBar, binding.swipeRefreshLayout,
binding.list, binding.motionLayout, binding.errorLayout, adapter)
//binding.progressBar.visibility = View.GONE
binding.swipeRefreshLayout.setOnRefreshListener {

View File

@ -67,7 +67,8 @@ open class UncachedFeedFragment<T: FeedContent> : BaseFragment() {
binding = FragmentFeedBinding.inflate(layoutInflater)
initAdapter(binding, adapter)
initAdapter(binding.progressBar, binding.swipeRefreshLayout, binding.list,
binding.motionLayout, binding.errorLayout, adapter)
binding.swipeRefreshLayout.setOnRefreshListener {
//It shouldn't be necessary to also retry() in addition to refresh(),

View File

@ -33,8 +33,5 @@ class ProfilePagingSource(
}
}
override fun getRefreshKey(state: PagingState<String, Status>): String? =
state.anchorPosition?.run {
state.closestItemToPosition(this)?.id
}
override fun getRefreshKey(state: PagingState<String, Status>): String? = null
}

View File

@ -9,8 +9,6 @@ import android.view.ViewGroup
import android.widget.*
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.core.view.size
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
@ -24,7 +22,7 @@ import com.h.pixeldroid.R
import com.h.pixeldroid.databinding.ActivityProfileBinding
import com.h.pixeldroid.databinding.FragmentProfilePostsBinding
import com.h.pixeldroid.posts.PostActivity
import com.h.pixeldroid.posts.feeds.ReposLoadStateAdapter
import com.h.pixeldroid.posts.feeds.initAdapter
import com.h.pixeldroid.posts.feeds.uncachedFeeds.FeedViewModel
import com.h.pixeldroid.posts.feeds.uncachedFeeds.UncachedContentRepository
import com.h.pixeldroid.posts.feeds.uncachedFeeds.profile.ProfileContentRepository
@ -88,14 +86,13 @@ class ProfileActivity : BaseActivity() {
).get(FeedViewModel::class.java) as FeedViewModel<Status>
profileAdapter = ProfilePostsAdapter()
initAdapter(binding, profileAdapter)
initAdapter(binding.profileProgressBar, binding.profileRefreshLayout,
binding.profilePostsRecyclerView, binding.motionLayout, binding.profileErrorLayout,
profileAdapter)
binding.profilePostsRecyclerView.layoutManager = GridLayoutManager(this, 3)
binding.profileRefreshLayout.setOnRefreshListener {
//It shouldn't be necessary to also retry() in addition to refresh(),
//but if we don't do this, reloads after an error fail immediately...
profileAdapter.retry()
profileAdapter.refresh()
}
@ -139,52 +136,6 @@ class ProfileActivity : BaseActivity() {
binding.profileRefreshLayout.isRefreshing = false
}
/**
* Initialises the [RecyclerView] adapter for the different FeedFragments.
*
* Makes the UI respond to various [LoadState]s, including errors when an error message is shown.
*/
internal fun <T: Any> initAdapter(binding: ActivityProfileBinding, adapter: PagingDataAdapter<T, RecyclerView.ViewHolder>) {
binding.profilePostsRecyclerView.adapter = adapter.withLoadStateFooter(
footer = ReposLoadStateAdapter { adapter.retry() }
)
adapter.addLoadStateListener { loadState ->
if(!binding.profileProgressBar.isVisible && binding.profileRefreshLayout.isRefreshing) {
// Stop loading spinner when loading is done
binding.profileRefreshLayout.isRefreshing = loadState.refresh is LoadState.Loading
} else {
// ProgressBar should stop showing as soon as the source stops loading ("source"
// meaning the database, so don't wait on the network)
val sourceLoading = loadState.source.refresh is LoadState.Loading
if(!sourceLoading && binding.profilePostsRecyclerView.size > 0){
binding.profilePostsRecyclerView.isVisible = true
binding.profileProgressBar.isVisible = false
} else if(binding.profilePostsRecyclerView.size == 0
&& loadState.append is LoadState.NotLoading
&& loadState.append.endOfPaginationReached){
binding.profileProgressBar.isVisible = false
showError(errorText = "Nothing to see here :(")
}
}
// Toast on any error, regardless of whether it came from RemoteMediator or PagingSource
val errorState = loadState.source.append as? LoadState.Error
?: loadState.source.prepend as? LoadState.Error
?: loadState.source.refresh as? LoadState.Error
?: loadState.append as? LoadState.Error
?: loadState.prepend as? LoadState.Error
?: loadState.refresh as? LoadState.Error
errorState?.let {
showError(errorText = it.error.toString())
}
if (errorState == null) showError(show = false, errorText = "")
}
}
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true

View File

@ -143,6 +143,7 @@
tools:visibility="visible">
<include
android:id="@+id/profileErrorLayout"
layout="@layout/error_layout"
tools:layout_editor_absoluteX="50dp" />