Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Extract code that binds the loadstate to a method #1254

Merged
merged 1 commit into from
Feb 1, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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