Skip to content

Instantly share code, notes, and snippets.

@MamboBryan
Created October 29, 2024 17:13
Show Gist options
  • Save MamboBryan/74f0d5fba7089d9db33945a89e54f9b3 to your computer and use it in GitHub Desktop.
Save MamboBryan/74f0d5fba7089d9db33945a89e54f9b3 to your computer and use it in GitHub Desktop.
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.paging.compose.LazyPagingItems
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.paging.CombinedLoadStates
import androidx.paging.LoadState
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.paging.LoadState
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Refresh
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@Composable
fun <T : Any> PagingComponent(
data: LazyPagingItems<T>,
modifier: Modifier = Modifier,
retry: () -> Unit = {},
refresh: () -> Unit = {},
empty: @Composable () -> Unit = {},
content: @Composable (T) -> Unit,
) {
Column(modifier = modifier) {
PagingLoadStatesComponent(
states = data.loadState,
count = data.itemCount,
modifier = Modifier.fillMaxWidth(),
retry = retry,
content = { index ->
val item = data[index]
item?.let { content(it) }
},
empty = empty,
)
}
}
@Composable
fun PagingLoadStatesComponent(
states: CombinedLoadStates,
count: Int,
modifier: Modifier = Modifier,
retry: () -> Unit = {},
retryPrepend: () -> Unit = {},
retryAppend: () -> Unit = {},
empty: @Composable () -> Unit = {},
content: @Composable (index: Int) -> Unit,
) {
val prepend = states.prepend
val refresh = states.refresh
val append = states.append
LazyVerticalGrid(columns = GridCells.Fixed(2), modifier = modifier) {
if (prepend !is LoadState.NotLoading) {
item { PagingLoadStateComponent(state = prepend, retry = retryPrepend) }
}
when (refresh) {
is LoadState.Error -> {
item {
CenteredColumn(
modifier =
Modifier
.fillMaxWidth()
.padding(24.dp),
) {
PagingLoadStateErrorComponent(throwable = refresh.error, retry = retry)
}
}
}
LoadState.Loading -> {
item {
CenteredColumn(modifier = Modifier.fillMaxWidth()) {
CircularProgressIndicator(modifier = Modifier.padding(16.dp))
}
}
}
is LoadState.NotLoading -> {
if (count == 0) {
item {
CenteredColumn(
modifier =
Modifier
.fillMaxWidth()
.padding(24.dp),
) {
empty()
}
}
} else {
items(count) { index ->
content(index)
}
}
}
}
if (append is LoadState.NotLoading) {
item { PagingLoadStateComponent(state = append, retry = retryAppend) }
}
}
}
@Composable
fun PagingLoadStateComponent(
state: LoadState,
modifier: Modifier = Modifier,
retry: () -> Unit = {},
content: @Composable (Boolean) -> Unit = {},
) {
CenteredColumn(
modifier = modifier,
) {
AnimatedContent(
modifier = Modifier.fillMaxWidth(),
targetState = state,
label = "paging load state",
) { value ->
when (value) {
LoadState.Loading -> {
CenteredColumn(modifier = Modifier.fillMaxWidth()) {
CircularProgressIndicator(modifier = Modifier.padding(16.dp))
}
}
is LoadState.Error -> {
PagingLoadStateErrorComponent(throwable = value.error, modifier = Modifier.padding(16.dp), retry = retry)
}
is LoadState.NotLoading -> {
content(value.endOfPaginationReached)
}
}
}
}
}
@Composable
fun PagingLoadStateErrorComponent(
throwable: Throwable,
modifier: Modifier = Modifier,
defaultError: String = "error",
retry: () -> Unit,
) {
CenteredColumn(modifier = modifier) {
Text(
text = throwable.message ?: defaultError,
modifier =
Modifier
.fillMaxWidth()
.padding(top = 16.dp),
textAlign = TextAlign.Center,
)
IconButton(modifier = Modifier.padding(8.dp), onClick = retry) {
Icon(
imageVector = Icons.Rounded.Refresh,
contentDescription = "refresh data",
)
}
}
}
@Composable
fun CenteredColumn(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.Center,
horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
content: @Composable ColumnScope.() -> Unit,
) {
Column(
modifier = modifier,
verticalArrangement = verticalArrangement,
horizontalAlignment = horizontalAlignment,
content = content,
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment