Skip to content

Add pagination samples #24

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 4 commits into from
Jul 23, 2024
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
11 changes: 11 additions & 0 deletions samples/pagination/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Pagination samples

This directory contains samples that demonstrate how to implement pagination with the Apollo normalized cache.

These are 3 variations of an Android app that uses the [GitHub GraphQL API](https://docs.github.com/en/graphql) to fetch and display a list of repositories.

- [manual](./manual): manually merge pages together and store the result into the cache using the [`ApolloStore`](https://apollographql.github.io/apollo-kotlin-normalized-cache-incubating/kdoc/normalized-cache-incubating/com.apollographql.cache.normalized/-apollo-store/index.html?query=interface%20ApolloStore) API.
- [pagination-support](./pagination-support): use the normalized cache pagination support (`@typePolicy(connectionFields: ...)` / [`ConnectionMetadataGenerator`](https://apollographql.github.io/apollo-kotlin-normalized-cache-incubating/kdoc/normalized-cache-incubating/com.apollographql.cache.normalized.api/-connection-metadata-generator/index.html?query=class%20ConnectionMetadataGenerator(connectionTypes:%20Set%3CString%3E)%20:%20MetadataGenerator), [`ConnectionRecordMerger`](https://apollographql.github.io/apollo-kotlin-normalized-cache-incubating/kdoc/normalized-cache-incubating/com.apollographql.cache.normalized.api/-connection-record-merger.html?query=val%20ConnectionRecordMerger:%20FieldRecordMerger)) to automatically merge pages together in the cache.
- [pagination-support-with-jetpack-paging](./pagination-support-with-jetpack-paging): demonstrates how to use the normalized cache pagination support along with the [Android Jetpack Paging library](https://developer.android.com/topic/libraries/architecture/paging/v3-overview).

Please refer to the `README.md` in each sample for more details.
9 changes: 9 additions & 0 deletions samples/pagination/manual/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.DS_Store
build
out
.gradle
*.iml
.idea/*
!.idea/copyright
!.idea/codeStyles
local.properties
17 changes: 17 additions & 0 deletions samples/pagination/manual/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Pagination sample: manual merging of pages

Displays a list of repositories fetched from the [GitHub GraphQL API](https://docs.github.com/en/graphql).

Note: to execute the app, provide a [GitHub access token](https://developer.github.com/v4/guides/forming-calls/#authenticating-with-graphql) in the `gradle.properties` file.

## Architecture

- `MainActivity` shows a `LazyColumn` listing the repositories by watching `RepositoryListQuery`.
- When scrolling to the end of the list, `fetchAndMergeNextPage()` is called, which
1. Gets the current list from the cache
2. Fetches the next page from the network
3. Manually merges the next page with the current list
4. Updates the cache with the merged list using the [`ApolloStore`](https://apollographql.github.io/apollo-kotlin-normalized-cache-incubating/kdoc/normalized-cache-incubating/com.apollographql.cache.normalized/-apollo-store/index.html?query=interface%20ApolloStore) API
- Writing to the cache triggers an emission to the watcher, and the `LazyColumn` is updated with the updated list.

The gist of it is [here](app/src/main/java/com/example/apollokotlinpaginationsample/repository/Apollo.kt#L43).
84 changes: 84 additions & 0 deletions samples/pagination/manual/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
fun prop(key: String) = project.findProperty(key).toString()

plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("com.apollographql.apollo").version("4.0.0-rc.2")
id("org.jetbrains.kotlin.plugin.compose").version("2.0.0")
}

android {
namespace = "com.example.apollokotlinpaginationsample"
compileSdk = 34

defaultConfig {
applicationId = "com.example.apollokotlinpaginationsample"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}

buildConfigField("String", "GITHUB_OAUTH_KEY", "\"${prop("githubOauthKey")}\"")
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}

compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}

kotlinOptions {
jvmTarget = "1.8"
}

buildFeatures {
compose = true
buildConfig = true
}

packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}

apollo {
service("main") {
packageName.set("com.example.apollokotlinpaginationsample.graphql")

introspection {
endpointUrl.set("https://api.github.com/graphql")
schemaFile.set(file("src/main/graphql/schema.graphqls"))
headers.put("Authorization", "Bearer ${prop("githubOauthKey")}")
}
}
}

dependencies {
implementation("androidx.core:core-ktx:1.13.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.3")
implementation("androidx.activity:activity-compose:1.9.0")
implementation(platform("androidx.compose:compose-bom:2024.06.00"))
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.3-SNAPSHOT")

debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
21 changes: 21 additions & 0 deletions samples/pagination/manual/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
31 changes: 31 additions & 0 deletions samples/pagination/manual/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".Application"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ApolloKotlinPaginationSample"
tools:targetApi="31">
<activity
android:name=".ui.MainActivity"
android:exported="true"
android:theme="@style/Theme.ApolloKotlinPaginationSample">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
11 changes: 11 additions & 0 deletions samples/pagination/manual/app/src/main/graphql/extra.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
extend schema
@link(
url: "https://specs.apollo.dev/kotlin_labs/v0.3",
import: ["@nonnull", "@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
@@ -0,0 +1,24 @@
query RepositoryListQuery($first: Int = 15, $after: String) {
organization(login: "github") {
repositories(first: $first, after: $after) {
pageInfo {
hasNextPage
endCursor
}
edges {
cursor
node {
...RepositoryFields
}
}
}
}
}

fragment RepositoryFields on Repository {
name
description
stargazers(first: 0) {
totalCount
}
}
Loading