Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ahmad-hamwi/lazy-pagination-compose

An intuitive and customizable Compose Multiplatform pagination composables that are built on top of lazy scrollables. Available on Android, iOS, MacOS, Linux, and Web.
https://github.com/ahmad-hamwi/lazy-pagination-compose

android cmp compose compose-multiplatform desktop ios javascript jvm kmp lazycolumn lazyrow linux macos pagination webassembly

Last synced: about 5 hours ago
JSON representation

An intuitive and customizable Compose Multiplatform pagination composables that are built on top of lazy scrollables. Available on Android, iOS, MacOS, Linux, and Web.

Awesome Lists containing this project

README

        

Lazy Pagination - Compose Multiplatform


API
API
API
API
API




API
API
API
API
API
API
API
API



An intuitive and customizable Compose Multiplatform pagination solution built on top of lazy composables and it extends their APIs.

Basically prefix your lazy composables such as `LazyColumn` or `LazyVerticalGrid` and more to add pagination support!

Two points where in mind while creating this library:
- Should have a simple and intuitive APIs with an easy learning curve.
- Can be placed in your Presentation/UI layer ONLY.

## Features ##

- Vertical & horizontal lists pagination using `PaginatedLazyColumn` & `PaginatedLazyRow` with the same original APIs.
- Vertical & horizontal grids pagination using `PaginatedLazyVerticalGrid` & `PaginatedLazyHorizontalGrid` with the same original APIs.
- Seamlessly integrate your pagination state with your your data layer.
- Generic fetching strategies such as
[offset-based](https://developer.box.com/guides/api-calls/pagination/offset-based/),
[cursor-based](https://jsonapi.org/profiles/ethanresnick/cursor-pagination/),
[time-based](https://developers.facebook.com/docs/graph-api/results/), etc...
- Resetting your pagination state using `refresh()` function
- Retrying your data fetches using `retryLastFailedRequest()` function

## Paginated Composables ##

### `PaginatedLazyColumn`: ###






Composable


```kotlin
PaginatedLazyColumn(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
// The rest of LazyColumn params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}
```

### `PaginatedLazyRow`: ###






Composable


```kotlin
PaginatedLazyRow(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
... // The rest of LazyRow params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}
```

### `PaginatedLazyVerticalGrid`: ###






Composable


```kotlin
PaginatedLazyVerticalGrid(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
... // The rest of LazyVerticalGrid params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}
```

### `PaginatedLazyHorizontalGrid`: ###






Composable


```kotlin
PaginatedLazyHorizontalGrid(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
... // The rest of LazyHorizontalGrid params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}
```


State in UI (no ViewModel)




```kotlin
// Int is passed as the KEY which represents your pagination fetching strategy
// Int example here means the page number but could really by anything such as a cursor, time, etc...
@Composable
fun Content() {
val paginationState = rememberPaginationState(
initialPageKey = 1,
onRequestPage = { pageKey: Int ->
scope.launch {
try {
val page = DataSource.getPage(pageNumber = pageKey, pageSize = 10)

appendPage(
items = page.items,
nextPageKey = page.nextPageNumber,
isLastPage = page.isLastPage
)
} catch (e: Exception) {
setError(e)
}
}
}
)

// Your paginated composable here
}
```


State in a ViewModel (Recommended)


```kotlin
class MyViewModel : ViewModel() {
// Int is passed as the KEY which represents your pagination fetching strategy
// Int example here means the page number but could really by anything such as a cursor, time, etc...
val paginationState = PaginationState(
initialPageKey = 1,
onRequestPage = { loadPage(it) }
)

fun loadPage(pageKey: Int) {
viewModelScope.launch {
try {
val page = DataSource.getPage(pageNumber = pageKey, pageSize = 10)

paginationState.appendPage(
items = page.items,
isLastPage = page.isLastPage
)
} catch (e: Exception) {
paginationState.setError(e)
}
}
}
}

@Composable
fun Content(viewModel: MyViewModel) {
val paginationState = viewModel.paginationState

// Your Paginated composable here
}
```

# Setup #

Get the latest version via Maven Central:

> (badge may not always be up to date, use the toml declaration for the latest release)

![Maven Central Version](https://img.shields.io/maven-central/v/io.github.ahmad-hamwi/lazy-pagination-compose)

Add Maven Central repository to your root build.gradle at the end of repositories:

```kotlin
allprojects {
repositories {
...
mavenCentral()
}
}
```

### For Compose Multiplatform Project ###

```toml
[versions]
lazy-pagination-compose = "1.3.7"

[libraries]
lazyPaginationCompose = { module = "io.github.ahmad-hamwi:lazy-pagination-compose", version.ref = "lazy-pagination-compose" }
```

```kotlin
// Compose Multiplatform
sourceSets {
commonMain.dependencies {
implementation(libs.lazyPaginationCompose)
}
}
```

For an Android Project use `io.github.ahmad-hamwi:lazy-pagination-compose-android`

# Usage #

### Full sample can be found in the [sample module](https://github.com/Ahmad-Hamwi/lazy-pagination-compose/tree/main/sample) ###

## 1- Prepare your pagination state ##

### Create a `PaginationState` by remembering it in your composable or holding it in your ViewModel.

```kotlin
// Int is the key which in this example represents the page number
val paginationState = rememberPaginationState(
initialPageKey = 1,
...
)
```

### Pass your `onRequestPage` callback when creating your `PaginationState` and call your data source ###

```kotlin
val scope = rememberCoroutineScope()

val paginationState = rememberPaginationState(
initialPageKey = 1,
onRequestPage = { pageKey: Int ->
scope.launch {
val page = DataSource.getPage(pageNumber = pageKey, pageSize = 10,)
}
}
)
```

### Append data using `appendPage` and flag the end of your list using `isLastPage` ###
```kotlin
val scope = rememberCoroutineScope()

val paginationState = rememberPaginationState(
initialPageKey = 1,
onRequestPage = { pageKey: Int ->
scope.launch {
val page = DataSource.getPage(pageNumber = pageKey, pageSize = 10,)

appendPage(
items = page.items,
nextPageKey = page.nextPageNumber,
isLastPage = page.isLastPage // optional, defaults to false
)
}
}
}
```

### Handle errors using `setError` ###
```kotlin
val paginationState = rememberPaginationState(
initialPageKey = 1,
onRequestPage = { pageKey: Int ->
scope.launch {
try {
val page = DataSource.getPage(pageNumber = pageKey, pageSize = 10,)

appendPage(
items = page.items,
nextPageKey = page.nextPageNumber,
isLastPage = page.isLastPage
)
} catch (e: Exception) {
setError(e)
}
}
}
)
```

## 2- Define your paginated composable ##

It can either be `PaginatedLazyColumn` or `PaginatedLazyRow` or `PaginatedLazyVerticalGrid` or `PaginatedLazyHorizontalGrid`

```kotlin
@Composable
fun Content() {
val paginationState = ... // either remembered here or in ViewModel

// Or any other paginated composable
PaginatedLazyColumn(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> ... },
newPageErrorIndicator = { e -> ... },
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}
}
```

### Retrying your last failed request can be through `retryLastFailedRequest` ###
```kotlin
paginationState.retryLastFailedRequest()
```

### Refreshing can be through `refresh` method ###
```kotlin
paginationState.refresh(
initialPageKey = 1 // optional, defaults to the value provided when creating the state
)
```

### More complex sample can be found in the [sample module](https://github.com/Ahmad-Hamwi/lazy-pagination-compose/tree/main/sample) ###

# Contributing #
This library is made to help other developers out in their app developments, feel free to contribute by suggesting ideas and creating issues and PRs that would make this repository more helpful.

# Honorable Mentions #
Thank you for the following contributors:
- [Tomislav Mladenov](https://github.com/TomislavMladenov): For adding support to the JS target.

# Support #
You can show support by either contributing to the repository or by buying me a cup of coffee!


Buy Me A Coffee

# License

Copyright (C) 2024 Ahmad Hamwi

Licensed under the MIT License