
Intuitive, customizable pagination solution built on lazy lists, automatically managing pagination states during scrolling. Includes error handling, retry, and refresh functionalities, ideal for seamless integration into UI or ViewModel.
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:
PaginatedLazyColumn & PaginatedLazyRow with the same original APIs.PaginatedLazyVerticalGrid & PaginatedLazyHorizontalGrid with the same original APIs.refresh() functionretryLastFailedRequest() functionPaginatedLazyColumn(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
// The rest of LazyColumn params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}PaginatedLazyRow(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
... // The rest of LazyRow params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}PaginatedLazyVerticalGrid(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
... // The rest of LazyVerticalGrid params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}PaginatedLazyHorizontalGrid(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
... // The rest of LazyHorizontalGrid params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}// 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<Int, Model>(
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
}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<Int, Model>(
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
}Get the latest version via Maven Central:
(badge may not always be up to date, use the toml declaration for the latest release)
Add Maven Central repository to your root build.gradle at the end of repositories:
allprojects {
repositories {
...
mavenCentral()
}
}[versions]
lazy-pagination-compose = "1.7.1"
[libraries]
lazyPaginationCompose = { module = "io.github.ahmad-hamwi:lazy-pagination-compose", version.ref = "lazy-pagination-compose" }// Compose Multiplatform
sourceSets {
commonMain.dependencies {
implementation(libs.lazyPaginationCompose)
}
}For an Android Project use io.github.ahmad-hamwi:lazy-pagination-compose-android
// Int is the key which in this example represents the page number
val paginationState = rememberPaginationState<Int, Model>(
initialPageKey = 1,
...
)val scope = rememberCoroutineScope()
val paginationState = rememberPaginationState<Int, Model>(
initialPageKey = 1,
onRequestPage = { pageKey: Int ->
scope.launch {
val page = DataSource.getPage(pageNumber = pageKey, pageSize = 10,)
}
}
)val scope = rememberCoroutineScope()
val paginationState = rememberPaginationState<Int, Model>(
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
)
}
}
}val paginationState = rememberPaginationState<Int, Model>(
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)
}
}
}
)It can either be PaginatedLazyColumn or PaginatedLazyRow or PaginatedLazyVerticalGrid or PaginatedLazyHorizontalGrid
@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 -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}
}paginationState.retryLastFailedRequest()paginationState.refresh(
initialPageKey = 1 // optional, defaults to the value provided when creating the state
)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.
Thank you for the following contributors:
You can show support by either contributing to the repository or by buying me a cup of coffee!
Copyright (C) 2024 Ahmad Hamwi
Licensed under the MIT License
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:
PaginatedLazyColumn & PaginatedLazyRow with the same original APIs.PaginatedLazyVerticalGrid & PaginatedLazyHorizontalGrid with the same original APIs.refresh() functionretryLastFailedRequest() functionPaginatedLazyColumn(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
// The rest of LazyColumn params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}PaginatedLazyRow(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
... // The rest of LazyRow params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}PaginatedLazyVerticalGrid(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
... // The rest of LazyVerticalGrid params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}PaginatedLazyHorizontalGrid(
paginationState = paginationState,
firstPageProgressIndicator = { ... },
newPageProgressIndicator = { ... },
firstPageErrorIndicator = { e -> // from setError
... e.message ...
... onRetry = { paginationState.retryLastFailedRequest() } ...
},
newPageErrorIndicator = { e -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
... // The rest of LazyHorizontalGrid params
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}// 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<Int, Model>(
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
}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<Int, Model>(
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
}Get the latest version via Maven Central:
(badge may not always be up to date, use the toml declaration for the latest release)
Add Maven Central repository to your root build.gradle at the end of repositories:
allprojects {
repositories {
...
mavenCentral()
}
}[versions]
lazy-pagination-compose = "1.7.1"
[libraries]
lazyPaginationCompose = { module = "io.github.ahmad-hamwi:lazy-pagination-compose", version.ref = "lazy-pagination-compose" }// Compose Multiplatform
sourceSets {
commonMain.dependencies {
implementation(libs.lazyPaginationCompose)
}
}For an Android Project use io.github.ahmad-hamwi:lazy-pagination-compose-android
// Int is the key which in this example represents the page number
val paginationState = rememberPaginationState<Int, Model>(
initialPageKey = 1,
...
)val scope = rememberCoroutineScope()
val paginationState = rememberPaginationState<Int, Model>(
initialPageKey = 1,
onRequestPage = { pageKey: Int ->
scope.launch {
val page = DataSource.getPage(pageNumber = pageKey, pageSize = 10,)
}
}
)val scope = rememberCoroutineScope()
val paginationState = rememberPaginationState<Int, Model>(
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
)
}
}
}val paginationState = rememberPaginationState<Int, Model>(
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)
}
}
}
)It can either be PaginatedLazyColumn or PaginatedLazyRow or PaginatedLazyVerticalGrid or PaginatedLazyHorizontalGrid
@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 -> ... },
firstPageEmptyIndicator = { ... },
newPageEmptyIndicator = { ... },
) {
itemsIndexed(
paginationState.allItems!!, // safe to access here
) { _, item ->
Item(value = item)
}
}
}paginationState.retryLastFailedRequest()paginationState.refresh(
initialPageKey = 1 // optional, defaults to the value provided when creating the state
)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.
Thank you for the following contributors:
You can show support by either contributing to the repository or by buying me a cup of coffee!
Copyright (C) 2024 Ahmad Hamwi
Licensed under the MIT License