From 26b1645d507cf1c891b7a32e422541238b1c37ca Mon Sep 17 00:00:00 2001 From: Nik Clayton Date: Sat, 1 Feb 2025 17:32:25 +0100 Subject: [PATCH] refactor: Extract code that binds the loadstate to a method (#1254) --- .../notifications/NotificationsFragment.kt | 80 +++++++++-------- .../components/timeline/TimelineFragment.kt | 89 ++++++++++--------- 2 files changed, 91 insertions(+), 78 deletions(-) diff --git a/app/src/main/java/app/pachli/components/notifications/NotificationsFragment.kt b/app/src/main/java/app/pachli/components/notifications/NotificationsFragment.kt index 692c3490e..7f4a52410 100644 --- a/app/src/main/java/app/pachli/components/notifications/NotificationsFragment.kt +++ b/app/src/main/java/app/pachli/components/notifications/NotificationsFragment.kt @@ -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 @@ -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) } } } @@ -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. diff --git a/app/src/main/java/app/pachli/components/timeline/TimelineFragment.kt b/app/src/main/java/app/pachli/components/timeline/TimelineFragment.kt index b3b67f1e2..932080c16 100644 --- a/app/src/main/java/app/pachli/components/timeline/TimelineFragment.kt +++ b/app/src/main/java/app/pachli/components/timeline/TimelineFragment.kt @@ -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 @@ -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) } } } @@ -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.