Refactor initAdapter
This commit is contained in:
parent
d13b34ed0d
commit
c2dd66c54f
@ -2,25 +2,32 @@ package com.h.pixeldroid.posts.feeds
|
|||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.view.size
|
import androidx.core.view.size
|
||||||
import androidx.paging.LoadState
|
import androidx.paging.LoadState
|
||||||
import androidx.paging.LoadStateAdapter
|
import androidx.paging.LoadStateAdapter
|
||||||
import androidx.paging.PagingDataAdapter
|
import androidx.paging.PagingDataAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
import com.h.pixeldroid.R
|
import com.h.pixeldroid.R
|
||||||
import com.h.pixeldroid.databinding.FragmentFeedBinding
|
import com.h.pixeldroid.databinding.ErrorLayoutBinding
|
||||||
import com.h.pixeldroid.databinding.LoadStateFooterViewItemBinding
|
import com.h.pixeldroid.databinding.LoadStateFooterViewItemBinding
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows or hides the error in the different FeedFragments
|
* Shows or hides the error in the different FeedFragments
|
||||||
*/
|
*/
|
||||||
private fun showError(errorText: String, show: Boolean = true, binding: FragmentFeedBinding){
|
private fun showError(
|
||||||
if(show){
|
errorText: String, show: Boolean = true,
|
||||||
binding.motionLayout.transitionToEnd()
|
motionLayout: MotionLayout,
|
||||||
binding.errorLayout.errorText.text = errorText
|
errorLayout: ErrorLayoutBinding){
|
||||||
} else if(binding.motionLayout.progress == 1F){
|
|
||||||
binding.motionLayout.transitionToStart()
|
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.
|
* 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>) {
|
internal fun <T: Any> initAdapter(
|
||||||
binding.list.adapter = adapter.withLoadStateFooter(
|
progressBar: ProgressBar, swipeRefreshLayout: SwipeRefreshLayout,
|
||||||
|
recyclerView: RecyclerView, motionLayout: MotionLayout, errorLayout: ErrorLayoutBinding,
|
||||||
|
adapter: PagingDataAdapter<T, RecyclerView.ViewHolder>) {
|
||||||
|
|
||||||
|
recyclerView.adapter = adapter.withLoadStateFooter(
|
||||||
footer = ReposLoadStateAdapter { adapter.retry() }
|
footer = ReposLoadStateAdapter { adapter.retry() }
|
||||||
)
|
)
|
||||||
|
|
||||||
adapter.addLoadStateListener { loadState ->
|
adapter.addLoadStateListener { loadState ->
|
||||||
|
|
||||||
if(!binding.progressBar.isVisible && binding.swipeRefreshLayout.isRefreshing) {
|
if(!progressBar.isVisible && swipeRefreshLayout.isRefreshing) {
|
||||||
// Stop loading spinner when loading is done
|
// Stop loading spinner when loading is done
|
||||||
binding.swipeRefreshLayout.isRefreshing = loadState.refresh is LoadState.Loading
|
swipeRefreshLayout.isRefreshing = loadState.refresh is LoadState.Loading
|
||||||
} else {
|
} else {
|
||||||
// ProgressBar should stop showing as soon as the source stops loading ("source"
|
// ProgressBar should stop showing as soon as the source stops loading ("source"
|
||||||
// meaning the database, so don't wait on the network)
|
// meaning the database, so don't wait on the network)
|
||||||
val sourceLoading = loadState.source.refresh is LoadState.Loading
|
val sourceLoading = loadState.source.refresh is LoadState.Loading
|
||||||
if(!sourceLoading && binding.list.size > 0){
|
if(!sourceLoading && recyclerView.size > 0){
|
||||||
binding.list.isVisible = true
|
recyclerView.isVisible = true
|
||||||
binding.progressBar.isVisible = false
|
progressBar.isVisible = false
|
||||||
} else if(binding.list.size == 0
|
} else if(recyclerView.size == 0
|
||||||
&& loadState.append is LoadState.NotLoading
|
&& loadState.append is LoadState.NotLoading
|
||||||
&& loadState.append.endOfPaginationReached){
|
&& loadState.append.endOfPaginationReached){
|
||||||
binding.progressBar.isVisible = false
|
progressBar.isVisible = false
|
||||||
showError(binding = binding, errorText = "Nothing to see here :(")
|
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.prepend as? LoadState.Error
|
||||||
?: loadState.refresh as? LoadState.Error
|
?: loadState.refresh as? LoadState.Error
|
||||||
errorState?.let {
|
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
|
* Adapter to the show the a [RecyclerView] item for a [LoadState], with a callback to retry if
|
||||||
* the retry button is pressed.
|
* the retry button is pressed.
|
||||||
|
@ -70,7 +70,8 @@ open class CachedFeedFragment<T: FeedContentDatabase> : BaseFragment() {
|
|||||||
|
|
||||||
binding = FragmentFeedBinding.inflate(layoutInflater)
|
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.progressBar.visibility = View.GONE
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||||
|
@ -67,7 +67,8 @@ open class UncachedFeedFragment<T: FeedContent> : BaseFragment() {
|
|||||||
|
|
||||||
binding = FragmentFeedBinding.inflate(layoutInflater)
|
binding = FragmentFeedBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
initAdapter(binding, adapter)
|
initAdapter(binding.progressBar, binding.swipeRefreshLayout, binding.list,
|
||||||
|
binding.motionLayout, binding.errorLayout, adapter)
|
||||||
|
|
||||||
binding.swipeRefreshLayout.setOnRefreshListener {
|
binding.swipeRefreshLayout.setOnRefreshListener {
|
||||||
//It shouldn't be necessary to also retry() in addition to refresh(),
|
//It shouldn't be necessary to also retry() in addition to refresh(),
|
||||||
|
@ -33,8 +33,5 @@ class ProfilePagingSource(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRefreshKey(state: PagingState<String, Status>): String? =
|
override fun getRefreshKey(state: PagingState<String, Status>): String? = null
|
||||||
state.anchorPosition?.run {
|
|
||||||
state.closestItemToPosition(this)?.id
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -9,8 +9,6 @@ import android.view.ViewGroup
|
|||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.core.view.size
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@ -24,7 +22,7 @@ import com.h.pixeldroid.R
|
|||||||
import com.h.pixeldroid.databinding.ActivityProfileBinding
|
import com.h.pixeldroid.databinding.ActivityProfileBinding
|
||||||
import com.h.pixeldroid.databinding.FragmentProfilePostsBinding
|
import com.h.pixeldroid.databinding.FragmentProfilePostsBinding
|
||||||
import com.h.pixeldroid.posts.PostActivity
|
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.FeedViewModel
|
||||||
import com.h.pixeldroid.posts.feeds.uncachedFeeds.UncachedContentRepository
|
import com.h.pixeldroid.posts.feeds.uncachedFeeds.UncachedContentRepository
|
||||||
import com.h.pixeldroid.posts.feeds.uncachedFeeds.profile.ProfileContentRepository
|
import com.h.pixeldroid.posts.feeds.uncachedFeeds.profile.ProfileContentRepository
|
||||||
@ -88,14 +86,13 @@ class ProfileActivity : BaseActivity() {
|
|||||||
).get(FeedViewModel::class.java) as FeedViewModel<Status>
|
).get(FeedViewModel::class.java) as FeedViewModel<Status>
|
||||||
|
|
||||||
profileAdapter = ProfilePostsAdapter()
|
profileAdapter = ProfilePostsAdapter()
|
||||||
initAdapter(binding, profileAdapter)
|
initAdapter(binding.profileProgressBar, binding.profileRefreshLayout,
|
||||||
|
binding.profilePostsRecyclerView, binding.motionLayout, binding.profileErrorLayout,
|
||||||
|
profileAdapter)
|
||||||
|
|
||||||
binding.profilePostsRecyclerView.layoutManager = GridLayoutManager(this, 3)
|
binding.profilePostsRecyclerView.layoutManager = GridLayoutManager(this, 3)
|
||||||
|
|
||||||
binding.profileRefreshLayout.setOnRefreshListener {
|
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()
|
profileAdapter.refresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,52 +136,6 @@ class ProfileActivity : BaseActivity() {
|
|||||||
binding.profileRefreshLayout.isRefreshing = false
|
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 {
|
override fun onSupportNavigateUp(): Boolean {
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
return true
|
return true
|
||||||
|
@ -143,6 +143,7 @@
|
|||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
|
|
||||||
<include
|
<include
|
||||||
|
android:id="@+id/profileErrorLayout"
|
||||||
layout="@layout/error_layout"
|
layout="@layout/error_layout"
|
||||||
tools:layout_editor_absoluteX="50dp" />
|
tools:layout_editor_absoluteX="50dp" />
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user