Skip to content

Commit

Permalink
refactor: Extract code that binds the loadstate to a method (#1254)
Browse files Browse the repository at this point in the history
  • Loading branch information
nikclayton authored Feb 1, 2025
1 parent 0ddc940 commit 26b1645
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.paging.CombinedLoadStates
import androidx.paging.LoadState
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
Expand Down Expand Up @@ -261,42 +262,7 @@ class NotificationsFragment :
}

// Update the UI from the loadState
adapter.loadStateFlow.distinctUntilChangedBy { it.refresh }.collect { loadState ->
when (loadState.refresh) {
is LoadState.Error -> {
binding.progressIndicator.hide()
binding.statusView.setup((loadState.refresh as LoadState.Error).error) {
adapter.retry()
}
binding.recyclerView.hide()
binding.statusView.show()
binding.swipeRefreshLayout.isRefreshing = false
}

LoadState.Loading -> {
/* nothing */
binding.statusView.hide()
binding.progressIndicator.show()
}

is LoadState.NotLoading -> {
// Might still be loading if source.refresh is Loading, so only update
// the UI when loading is completely quiet.
if (loadState.source.refresh !is LoadState.Loading) {
binding.progressIndicator.hide()
binding.swipeRefreshLayout.isRefreshing = false
if (adapter.itemCount == 0) {
binding.statusView.setup(BackgroundMessage.Empty())
binding.recyclerView.hide()
binding.statusView.show()
} else {
binding.statusView.hide()
binding.recyclerView.show()
}
}
}
}
}
adapter.loadStateFlow.distinctUntilChangedBy { it.refresh }.collect(::bindLoadState)
}
}
}
Expand Down Expand Up @@ -371,6 +337,48 @@ class NotificationsFragment :
}
}

/**
* Binds [CombinedLoadStates] to the UI.
*
* Updates the UI based on the contents of [loadState.refresh][CombinedLoadStates.refresh]
* to show/hide Error, Loading, and NotLoading states.
*/
private fun bindLoadState(loadState: CombinedLoadStates) {
when (loadState.refresh) {
is LoadState.Error -> {
binding.progressIndicator.hide()
binding.statusView.setup((loadState.refresh as LoadState.Error).error) {
adapter.retry()
}
binding.recyclerView.hide()
binding.statusView.show()
binding.swipeRefreshLayout.isRefreshing = false
}

LoadState.Loading -> {
binding.statusView.hide()
binding.progressIndicator.show()
}

is LoadState.NotLoading -> {
// Might still be loading if source.refresh is Loading, so only update
// the UI when loading is completely quiet.
if (loadState.source.refresh !is LoadState.Loading) {
binding.progressIndicator.hide()
binding.swipeRefreshLayout.isRefreshing = false
if (adapter.itemCount == 0) {
binding.statusView.setup(BackgroundMessage.Empty())
binding.recyclerView.hide()
binding.statusView.show()
} else {
binding.statusView.hide()
binding.recyclerView.show()
}
}
}
}
}

/**
* Refreshes the adapter, waits for the first page to be updated, and scrolls the
* recyclerview to the first notification that was visible before the refresh.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.lifecycle.viewmodel.MutableCreationExtras
import androidx.paging.CombinedLoadStates
import androidx.paging.LoadState
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
Expand Down Expand Up @@ -270,48 +271,7 @@ class TimelineFragment :
}
}

adapter.loadStateFlow.distinctUntilChangedBy { it.refresh }.collect { loadState ->
when (loadState.refresh) {
is LoadState.Error -> {
binding.progressIndicator.hide()
binding.statusView.setup((loadState.refresh as LoadState.Error).error) {
adapter.retry()
}
binding.recyclerView.hide()
binding.statusView.show()
binding.swipeRefreshLayout.isRefreshing = false
}

LoadState.Loading -> {
/* nothing */
binding.statusView.hide()
binding.progressIndicator.show()
}

is LoadState.NotLoading -> {
// Might still be loading if source.refresh is Loading, so only update
// the UI when loading is completely quiet.
Timber.d("NotLoading .refresh: ${loadState.refresh}")
Timber.d(" NotLoading .source.refresh: ${loadState.source.refresh}")
Timber.d(" NotLoading .mediator.refresh: ${loadState.mediator?.refresh}")
if (loadState.source.refresh !is LoadState.Loading) {
binding.progressIndicator.hide()
binding.swipeRefreshLayout.isRefreshing = false
if (adapter.itemCount == 0) {
binding.statusView.setup(BackgroundMessage.Empty())
if (timeline == Timeline.Home) {
binding.statusView.showHelp(R.string.help_empty_home)
}
binding.recyclerView.hide()
binding.statusView.show()
} else {
binding.statusView.hide()
binding.recyclerView.show()
}
}
}
}
}
adapter.loadStateFlow.distinctUntilChangedBy { it.refresh }.collect(::bindLoadState)
}
}
}
Expand Down Expand Up @@ -425,6 +385,51 @@ class TimelineFragment :
}
}

/**
* Binds [CombinedLoadStates] to the UI.
*
* Updates the UI based on the contents of [loadState.refresh][CombinedLoadStates.refresh]
* to show/hide Error, Loading, and NotLoading states.
*/
private fun bindLoadState(loadState: CombinedLoadStates) {
when (loadState.refresh) {
is LoadState.Error -> {
binding.progressIndicator.hide()
binding.statusView.setup((loadState.refresh as LoadState.Error).error) {
adapter.retry()
}
binding.recyclerView.hide()
binding.statusView.show()
binding.swipeRefreshLayout.isRefreshing = false
}

LoadState.Loading -> {
binding.statusView.hide()
binding.progressIndicator.show()
}

is LoadState.NotLoading -> {
// Might still be loading if source.refresh is Loading, so only update
// the UI when loading is completely quiet.
if (loadState.source.refresh !is LoadState.Loading) {
binding.progressIndicator.hide()
binding.swipeRefreshLayout.isRefreshing = false
if (adapter.itemCount == 0) {
binding.statusView.setup(BackgroundMessage.Empty())
if (timeline == Timeline.Home) {
binding.statusView.showHelp(R.string.help_empty_home)
}
binding.recyclerView.hide()
binding.statusView.show()
} else {
binding.statusView.hide()
binding.recyclerView.show()
}
}
}
}
}

/**
* Refreshes the adapter, waits for the first page to be updated, and scrolls the
* recyclerview to the first status that was visible before the refresh.
Expand Down

0 comments on commit 26b1645

Please sign in to comment.