Skip to content

Update pagination samples #115

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

Merged
merged 3 commits into from
Apr 2, 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
10 changes: 5 additions & 5 deletions samples/pagination/manual/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ fun prop(key: String) = project.findProperty(key).toString()
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.apollographql.apollo").version("4.1.0")
id("org.jetbrains.kotlin.plugin.compose").version("2.0.21")
id("com.apollographql.apollo").version("4.1.1")
id("org.jetbrains.kotlin.plugin.compose").version("2.1.10")
}

android {
Expand Down Expand Up @@ -69,15 +69,15 @@ apollo {
dependencies {
implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
implementation("androidx.activity:activity-compose:1.9.3")
implementation(platform("androidx.compose:compose-bom:2024.10.01"))
implementation("androidx.activity:activity-compose:1.10.1")
implementation(platform("androidx.compose:compose-bom:2025.03.01"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")

implementation("com.apollographql.apollo:apollo-runtime")
implementation("com.apollographql.cache:normalized-cache-sqlite-incubating:0.0.4")
implementation("com.apollographql.cache:normalized-cache-sqlite-incubating:0.0.8")

debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
extend schema
@link(
url: "https://specs.apollo.dev/kotlin_labs/v0.3",
import: ["@nonnull", "@typePolicy"]
import: ["@typePolicy"]
)

extend type Query @nonnull(fields: "organization")
extend type RepositoryConnection @nonnull(fields: "edges")
extend type RepositoryEdge @nonnull(fields: "node")

extend type Repository @typePolicy(keyFields: "id")
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,22 @@ suspend fun fetchAndMergeNextPage() {
val cacheResponse = apolloClient.query(listQuery).fetchPolicy(FetchPolicy.CacheOnly).execute()

// 2. Fetch the next page from the network (don't update the cache yet)
val after = cacheResponse.data!!.organization.repositories.pageInfo.endCursor
val after = cacheResponse.data!!.organization!!.repositories.pageInfo.endCursor
val networkResponse = apolloClient.query(RepositoryListQuery(after = Optional.presentIfNotNull(after))).fetchPolicy(FetchPolicy.NetworkOnly).execute()

// 3. Merge the next page with the current list
val mergedList = cacheResponse.data!!.organization.repositories.edges + networkResponse.data!!.organization.repositories.edges
val mergedList = cacheResponse.data!!.organization!!.repositories.edges!! + networkResponse.data!!.organization!!.repositories.edges!!
val dataWithMergedList = networkResponse.data!!.copy(
organization = networkResponse.data!!.organization.copy(
repositories = networkResponse.data!!.organization.repositories.copy(
pageInfo = networkResponse.data!!.organization.repositories.pageInfo,
organization = networkResponse.data!!.organization!!.copy(
repositories = networkResponse.data!!.organization!!.repositories.copy(
pageInfo = networkResponse.data!!.organization!!.repositories.pageInfo,
edges = mergedList
)
)
)

// 4. Update the cache with the merged list
apolloClient.apolloStore.writeOperation(operation = listQuery, operationData = dataWithMergedList).also { keys ->
apolloClient.apolloStore.writeOperation(operation = listQuery, data = dataWithMergedList).also { keys ->
apolloClient.apolloStore.publish(keys)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.apollographql.apollo.api.ApolloResponse
import com.apollographql.apollo.exception.CacheMissException
import com.apollographql.cache.normalized.FetchPolicy
import com.apollographql.cache.normalized.fetchPolicy
import com.apollographql.cache.normalized.watch
import com.apollographql.apollo.exception.CacheMissException
import com.example.apollokotlinpaginationsample.R
import com.example.apollokotlinpaginationsample.graphql.RepositoryListQuery
import com.example.apollokotlinpaginationsample.graphql.fragment.RepositoryFields
Expand Down Expand Up @@ -84,11 +84,11 @@ private fun RefreshBanner() {
@Composable
private fun RepositoryList(response: ApolloResponse<RepositoryListQuery.Data>) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(response.data!!.organization.repositories.edges.map { it!!.node.repositoryFields }) {
items(response.data!!.organization!!.repositories.edges!!.map { it!!.node!!.repositoryFields }) {
RepositoryItem(it)
}
item {
if (response.data!!.organization.repositories.pageInfo.hasNextPage) {
if (response.data!!.organization!!.repositories.pageInfo.hasNextPage) {
LoadingItem()
LaunchedEffect(Unit) {
fetchAndMergeNextPage()
Expand Down
4 changes: 2 additions & 2 deletions samples/pagination/manual/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.7.2" apply false
id("org.jetbrains.kotlin.android") version "2.0.21" apply false
id("com.android.application") version "8.9.1" apply false
id("org.jetbrains.kotlin.android") version "2.1.10" apply false
}
2 changes: 1 addition & 1 deletion samples/pagination/manual/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ kotlin.code.style=official
android.nonTransitiveRClass=true

# Get a Github API Oauth token here: https://github.com/settings/tokens
githubOauthKey=XXXXXXXXXXX
#githubOauthKey=XXXXXXXXXXX
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Fri Jan 19 14:54:45 CET 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ fun prop(key: String) = project.findProperty(key).toString()
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.apollographql.apollo").version("4.1.0")
id("org.jetbrains.kotlin.plugin.compose").version("2.0.21")
id("com.apollographql.apollo").version("4.1.1")
id("org.jetbrains.kotlin.plugin.compose").version("2.1.10")
}

android {
Expand Down Expand Up @@ -69,18 +69,18 @@ apollo {
dependencies {
implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
implementation("androidx.activity:activity-compose:1.9.3")
implementation(platform("androidx.compose:compose-bom:2024.10.01"))
implementation("androidx.activity:activity-compose:1.10.1")
implementation(platform("androidx.compose:compose-bom:2025.03.01"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")

implementation("com.apollographql.apollo:apollo-runtime")
implementation("com.apollographql.cache:normalized-cache-sqlite-incubating:0.0.4")
implementation("com.apollographql.cache:normalized-cache-sqlite-incubating:0.0.8")

implementation("androidx.paging:paging-runtime-ktx:3.3.2")
implementation("androidx.paging:paging-compose:3.3.2")
implementation("androidx.paging:paging-runtime-ktx:3.3.6")
implementation("androidx.paging:paging-compose:3.3.6")

debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
extend schema
@link(
url: "https://specs.apollo.dev/kotlin_labs/v0.3",
import: ["@nonnull", "@typePolicy"]
import: ["@typePolicy"]
)

extend type Query @nonnull(fields: "organization")
extend type RepositoryConnection @nonnull(fields: "edges")
extend type RepositoryEdge @nonnull(fields: "node")

extend type Repository @typePolicy(keyFields: "id")

extend type Organization @typePolicy(connectionFields: "repositories")
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import com.apollographql.cache.normalized.ApolloStore
import com.apollographql.cache.normalized.FetchPolicy
import com.apollographql.cache.normalized.api.ConnectionMetadataGenerator
import com.apollographql.cache.normalized.api.ConnectionRecordMerger
import com.apollographql.cache.normalized.api.FieldPolicyCacheResolver
import com.apollographql.cache.normalized.api.TypePolicyCacheKeyGenerator
import com.apollographql.cache.normalized.fetchPolicy
import com.apollographql.cache.normalized.memory.MemoryCacheFactory
import com.apollographql.cache.normalized.sql.SqlNormalizedCacheFactory
Expand Down Expand Up @@ -52,9 +50,7 @@ val apolloClient: ApolloClient by lazy {
.store(
ApolloStore(
normalizedCacheFactory = memoryThenSqlCache,
cacheKeyGenerator = TypePolicyCacheKeyGenerator,
metadataGenerator = ConnectionMetadataGenerator(Pagination.connectionTypes),
cacheResolver = FieldPolicyCacheResolver,
recordMerger = ConnectionRecordMerger
)
)
Expand Down Expand Up @@ -91,7 +87,8 @@ class RepositoryRemoteMediator : RemoteMediator<String, RepositoryListQuery.Edge
}
}

val loadSize = if (loadType == LoadType.REFRESH) state.config.initialLoadSize else state.config.pageSize
val loadSize =
if (loadType == LoadType.REFRESH) state.config.initialLoadSize else state.config.pageSize
val response = apolloClient.query(
RepositoryListQuery(
after = Optional.presentIfNotNull(lastItemCursor),
Expand All @@ -101,9 +98,11 @@ class RepositoryRemoteMediator : RemoteMediator<String, RepositoryListQuery.Edge
.fetchPolicy(FetchPolicy.NetworkOnly)
.execute()
if (response.data != null) {
return MediatorResult.Success(endOfPaginationReached = response.data!!.organization.repositories.edges.size < loadSize)
return MediatorResult.Success(endOfPaginationReached = response.data!!.organization!!.repositories.edges!!.size < loadSize)
}
return MediatorResult.Error(response.exception ?: ApolloGraphQLException(response.errors!!.first()))
return MediatorResult.Error(
response.exception ?: ApolloGraphQLException(response.errors!!.first())
)
}
}

Expand Down Expand Up @@ -169,7 +168,13 @@ class RepositoryPagingSource(
}

override fun getRefreshKey(state: PagingState<String, RepositoryListQuery.Edge>): String? {
return state.anchorPosition?.let { state.closestItemToPosition((it - state.config.initialLoadSize / 2).coerceAtLeast(0)) }?.cursor
return state.anchorPosition?.let {
state.closestItemToPosition(
(it - state.config.initialLoadSize / 2).coerceAtLeast(
0
)
)
}?.cursor
}

override val keyReuseSupported = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ class MainActivity : ComponentActivity() {
},
).flow
setContent {
val repositoryPagingItems: LazyPagingItems<RepositoryListQuery.Edge> = repositoryPagingData.collectAsLazyPagingItems()
val repositoryPagingItems: LazyPagingItems<RepositoryListQuery.Edge> =
repositoryPagingData.collectAsLazyPagingItems()
MaterialTheme {
Column(modifier = Modifier.fillMaxSize()) {
RefreshBanner(repositoryPagingItems)
Expand Down Expand Up @@ -80,10 +81,10 @@ private fun RepositoryList(repositoryPagingItems: LazyPagingItems<RepositoryList
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(
count = repositoryPagingItems.itemCount,
key = repositoryPagingItems.itemKey { it.node.id },
key = repositoryPagingItems.itemKey { it.node!!.id },
) { index ->
val edge: RepositoryListQuery.Edge = repositoryPagingItems[index]!!
RepositoryItem(edge.node.repositoryFields)
RepositoryItem(edge.node!!.repositoryFields)
}

if (repositoryPagingItems.loadState.append == LoadState.Loading) {
Expand All @@ -100,7 +101,10 @@ private fun RepositoryItem(repositoryFields: RepositoryFields) {
headlineContent = {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(modifier = Modifier.weight(1F), text = repositoryFields.name)
Text(text = repositoryFields.stargazers.totalCount.toString(), style = MaterialTheme.typography.bodyMedium)
Text(
text = repositoryFields.stargazers.totalCount.toString(),
style = MaterialTheme.typography.bodyMedium
)
Icon(
painter = painterResource(R.drawable.ic_star_black_16dp),
contentDescription = null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.7.2" apply false
id("org.jetbrains.kotlin.android") version "2.0.21" apply false
id("com.android.application") version "8.9.1" apply false
id("org.jetbrains.kotlin.android") version "2.1.10" apply false
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,4 @@ kotlin.code.style=official
android.nonTransitiveRClass=true

# Get a Github API Oauth token here: https://github.com/settings/tokens
githubOauthKey=ghp_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

#githubOauthKey=XXXXXXXXXXX
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Fri Jan 19 14:54:45 CET 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
10 changes: 5 additions & 5 deletions samples/pagination/pagination-support/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ fun prop(key: String) = project.findProperty(key).toString()
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.apollographql.apollo").version("4.1.0")
id("org.jetbrains.kotlin.plugin.compose").version("2.0.21")
id("com.apollographql.apollo").version("4.1.1")
id("org.jetbrains.kotlin.plugin.compose").version("2.1.10")
}

android {
Expand Down Expand Up @@ -69,15 +69,15 @@ apollo {
dependencies {
implementation("androidx.core:core-ktx:1.15.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
implementation("androidx.activity:activity-compose:1.9.3")
implementation(platform("androidx.compose:compose-bom:2024.10.01"))
implementation("androidx.activity:activity-compose:1.10.1")
implementation(platform("androidx.compose:compose-bom:2025.03.01"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")

implementation("com.apollographql.apollo:apollo-runtime")
implementation("com.apollographql.cache:normalized-cache-sqlite-incubating:0.0.4")
implementation("com.apollographql.cache:normalized-cache-sqlite-incubating:0.0.8")

debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
extend schema
@link(
url: "https://specs.apollo.dev/kotlin_labs/v0.3",
import: ["@nonnull", "@typePolicy"]
import: ["@typePolicy"]
)

extend type Query @nonnull(fields: "organization")
extend type RepositoryConnection @nonnull(fields: "edges")
extend type RepositoryEdge @nonnull(fields: "node")

extend type Repository @typePolicy(keyFields: "id")

extend type Organization @typePolicy(connectionFields: "repositories")
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ val apolloClient: ApolloClient by lazy {
.store(
ApolloStore(
normalizedCacheFactory = memoryThenSqlCache,
cacheKeyGenerator = TypePolicyCacheKeyGenerator,
metadataGenerator = ConnectionMetadataGenerator(Pagination.connectionTypes),
cacheResolver = FieldPolicyCacheResolver,
recordMerger = ConnectionRecordMerger
)
)
Expand All @@ -56,6 +54,6 @@ suspend fun fetchAndMergeNextPage() {
val cacheResponse = apolloClient.query(listQuery).fetchPolicy(FetchPolicy.CacheOnly).execute()

// 2. Fetch the next page from the network and store it in the cache
val after = cacheResponse.data!!.organization.repositories.pageInfo.endCursor
val after = cacheResponse.data!!.organization!!.repositories.pageInfo.endCursor
apolloClient.query(RepositoryListQuery(after = Optional.presentIfNotNull(after))).fetchPolicy(FetchPolicy.NetworkOnly).execute()
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.apollographql.apollo.api.ApolloResponse
import com.apollographql.apollo.exception.CacheMissException
import com.apollographql.cache.normalized.FetchPolicy
import com.apollographql.cache.normalized.fetchPolicy
import com.apollographql.cache.normalized.watch
import com.apollographql.apollo.exception.CacheMissException
import com.example.apollokotlinpaginationsample.R
import com.example.apollokotlinpaginationsample.graphql.RepositoryListQuery
import com.example.apollokotlinpaginationsample.graphql.fragment.RepositoryFields
Expand Down Expand Up @@ -84,11 +84,11 @@ private fun RefreshBanner() {
@Composable
private fun RepositoryList(response: ApolloResponse<RepositoryListQuery.Data>) {
LazyColumn(modifier = Modifier.fillMaxSize()) {
items(response.data!!.organization.repositories.edges.map { it!!.node.repositoryFields }) {
items(response.data!!.organization!!.repositories.edges!!.map { it!!.node!!.repositoryFields }) {
RepositoryItem(it)
}
item {
if (response.data!!.organization.repositories.pageInfo.hasNextPage) {
if (response.data!!.organization!!.repositories.pageInfo.hasNextPage) {
LoadingItem()
LaunchedEffect(Unit) {
fetchAndMergeNextPage()
Expand Down
4 changes: 2 additions & 2 deletions samples/pagination/pagination-support/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.7.2" apply false
id("org.jetbrains.kotlin.android") version "2.0.21" apply false
id("com.android.application") version "8.9.1" apply false
id("org.jetbrains.kotlin.android") version "2.1.10" apply false
}
3 changes: 1 addition & 2 deletions samples/pagination/pagination-support/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,4 @@ kotlin.code.style=official
android.nonTransitiveRClass=true

# Get a Github API Oauth token here: https://github.com/settings/tokens
githubOauthKey=XXXXXXXXXXX

#githubOauthKey=XXXXXXXXXXX
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Fri Jan 19 14:54:45 CET 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists