Skip to content

feat(android): platform-owned GraphQL consumption#115

Merged
up-tandem merged 7 commits intomainfrom
android/issue-81-graphql-consumption
Mar 2, 2026
Merged

feat(android): platform-owned GraphQL consumption#115
up-tandem merged 7 commits intomainfrom
android/issue-81-graphql-consumption

Conversation

@up-tandem
Copy link
Copy Markdown
Contributor

@up-tandem up-tandem commented Feb 25, 2026

Summary

  • Add Apollo Kotlin codegen with platform-owned GraphQL operations (ExperienceBySlug, Experiences)
  • Implement GraphQLContentClient adapter with bearer-token auth via HTTP interceptor
  • Source schema from apps/cms/schema.graphql for type-safe code generation
  • Add feature parity checklist to README

Builds on #80

Resolves #81

Test plan

  • Run ./gradlew :app:assembleDebug and confirm BUILD SUCCESSFUL
  • Verify Apollo codegen generates typed models from .graphql operations
  • Verify GraphQLContentClient compiles with correct Apollo API usage
  • Review generated schema types match CMS schema

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation

    • Added a detailed Android README covering GraphQL integration, local build, requirements, and parity checklist with iOS.
  • New Features

    • Apollo GraphQL client and operations for CMS content (queries for experiences and experience-by-slug).
    • Compose-based UI with a MainActivity entry, Material3 theme, and basic home string resources.
    • Content client supporting locale-aware fetching and pagination.
  • Build Configuration

    • Enabled GraphQL codegen, buildConfig keys for endpoint/token, Java 17, and SDK 34.
  • Chores

    • Updated .gitignore and editor config for Compose.

up-tandem and others added 3 commits February 24, 2026 11:33
- Add AndroidManifest.xml with launcher activity and app_name/theme refs
- Add MainActivity (ComponentActivity + setContent + enableEdgeToEdge)
- Add ForgeTheme using Material3 lightColorScheme/darkColorScheme
- Add res/values/strings.xml and themes.xml
- Enable Compose buildFeatures + composeOptions (compiler 1.5.15)
- Wire Compose BOM 2024.09.00; add material3 and tooling deps
- Update README with assembleDebug / installDebug build commands

Resolves #80

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add gradle.properties: android.useAndroidX=true (was missing; AAPT
  rejected AndroidX deps at runtime classpath check)
- Fix themes.xml parent: Theme.Material.NoTitleBar → Theme.Material.Light.NoActionBar
  (NoTitleBar variant does not exist in the platform resource set)
- Add compileOptions (sourceCompatibility/targetCompatibility = 17) and
  kotlinOptions (jvmTarget = 17) to app/build.gradle.kts to resolve
  JVM-target mismatch between compileDebugJavaWithJavac (1.8 default)
  and compileDebugKotlin (21 from local JDK)

assembleDebug now completes: BUILD SUCCESSFUL

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Apollo Kotlin codegen with platform-owned operations (ExperienceBySlug,
Experiences) sourced from apps/cms/schema.graphql. Implement GraphQLContentClient
adapter with bearer-token auth via HTTP interceptor. Add parity checklist to README.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 25, 2026

Warning

Rate limit exceeded

@up-tandem has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 59 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 35fa85d and 581073b.

📒 Files selected for processing (3)
  • .gitignore
  • mobile/android/README.md
  • mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt

Walkthrough

Adds Android Apollo Kotlin GraphQL integration: platform-owned operations, Apollo codegen and Gradle setup, a GraphQLContentClient with bearer-token auth, two GraphQL queries, a Compose entry activity and theme, resources, and related docs/config.

Changes

Cohort / File(s) Summary
Documentation
mobile/android/README.md
New detailed README: Apollo Kotlin integration, codegen/schema source, build requirements, local build steps, GRAPHQL_ENDPOINT/TOKEN config, and Android↔iOS parity checklist.
Top-level Build
mobile/android/build.gradle.kts, mobile/android/gradle.properties
Register Apollo Gradle plugin (com.apollographql.apollo 4.1.0) and add Android/Gradle properties (AndroidX, JVM args, Kotlin style).
App Build & Dependencies
mobile/android/app/build.gradle.kts
App-level Apollo service configured, buildConfig fields for GRAPHQL_ENDPOINT/GRAPHQL_TOKEN, Compose BOM and Material3 deps, Java/Kotlin target set to 17, and apollo-runtime dependency.
GraphQL Operations
mobile/android/app/src/main/graphql/ExperienceBySlug.graphql, mobile/android/app/src/main/graphql/Experiences.graphql
Added platform-owned queries: ExperienceBySlug (sections union with fragments) and Experiences (paginated list).
GraphQL Client Implementation
mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt
New Apollo-backed GraphQLContentClient implementing ContentClient with suspend getContent/listExperiences, mapping results to MobileContentItem, plus AuthInterceptor and close().
UI Entry & Theme
mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt, mobile/android/app/src/main/kotlin/com/forge/mobile/ui/theme/Theme.kt
MainActivity (Compose) added; ForgeTheme composable using Material3 color schemes and system dark-mode selection.
Android Manifest & Resources
mobile/android/app/src/main/AndroidManifest.xml, mobile/android/app/src/main/res/values/strings.xml, mobile/android/app/src/main/res/values/themes.xml
New manifest declaring exported MainActivity launcher with Theme.Forge; string resources (app_name, home_title); theme resource added.
Editor & VCS Config
.gitignore, mobile/android/.gitignore, mobile/android/.editorconfig
Ignore local.properties, build artifacts, Apollo schema copy; add ktlint exception for @Composable naming.

Sequence Diagram

sequenceDiagram
    participant MA as MainActivity
    participant GCC as GraphQLContentClient
    participant Apollo as Apollo Client
    participant Auth as AuthInterceptor
    participant API as CMS GraphQL API

    MA->>GCC: getContent(locale, slug)
    GCC->>Apollo: execute(ExperienceBySlugQuery)
    Apollo->>Auth: intercept(request)
    Auth->>API: HTTP POST (Authorization: Bearer ...)
    API-->>Auth: GraphQL response
    Auth-->>Apollo: response
    Apollo-->>GCC: ExperienceBySlug result
    GCC->>GCC: map to MobileContentItem
    GCC-->>MA: MobileContentItem?

    MA->>GCC: listExperiences(locale, page, pageSize)
    GCC->>Apollo: execute(ExperiencesQuery)
    Apollo->>Auth: intercept(request)
    Auth->>API: HTTP POST (Authorization: Bearer ...)
    API-->>Auth: GraphQL response
    Auth-->>Apollo: response
    Apollo-->>GCC: Experiences result
    GCC->>GCC: map to List<MobileContentItem>
    GCC-->>MA: List<MobileContentItem>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: implementing platform-owned GraphQL consumption for the Android platform.
Linked Issues check ✅ Passed The PR fully addresses all acceptance criteria in issue #81: Android defines platform-owned GraphQL operations, implements a ContentClient adapter with bearer-token auth, includes documentation updates, and maintains no shared operation files.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing Android GraphQL consumption as specified in issue #81. No unrelated or out-of-scope modifications were detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch android/issue-81-graphql-consumption

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added the tooling label Feb 25, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@mobile/android/app/build.gradle.kts`:
- Around line 25-26: The build currently injects a static secret via
buildConfigField("String", "GRAPHQL_TOKEN", ...), which compiles the token into
the APK; remove any non-empty default for GRAPHQL_TOKEN in the build.gradle.kts
and stop shipping credentials in BuildConfig.GROUPQL_TOKEN; instead retrieve
tokens at runtime (e.g., user/session token from authenticated backend or a
secure backend proxy) or inject per-build secrets via CI/properties without
embedding them in source (use an empty default and load real token from a secure
runtime source).

In `@mobile/android/app/src/main/graphql/schema.graphqls`:
- Around line 1-1153: Generated GraphQL schema ("This file was generated by
Nexus Schema") is failing Prettier CI; update the generation pipeline so the
produced schema is consistently formatted or explicitly excluded from Prettier.
Fix by either: (A) integrating Prettier formatting into the schema generation
step used by schema-sync/codegen so the output of the generator (the generated
schema file) is run through Prettier before committing, or (B) adding the
generated schema pattern to Prettier ignore rules so CI skips it; update the
schema generation task or .prettierignore entry accordingly and ensure the
change addresses the Prettier CI warning.
- Around line 1-3: This file is a committed duplicate of the Strapi-generated
schema (schema.graphqls) and should be removed; instead update the Apollo
codegen/config so it consumes the canonical Strapi schema at
apps/cms/**/schema.graphql (or add a build/CI sync step that copies the
canonical schema into the mobile build) and delete the duplicate
mobile/android/app/src/main/graphql/schema.graphqls; ensure any references in
the Apollo/GraphQL generation step point to the canonical Strapi-generated
schema to avoid drift.

In `@mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt`:
- Around line 38-45: The current mapper for computing body returns an empty
string inside mapNotNull which counts as a non-null result and may cause an
empty value to be chosen first; update the mapping logic in
GraphQLContentClient.kt (the variable body creation) so each branch returns null
when there is no actual content (e.g., change the InfoBlocks branch to return
section.description ?: section.heading ?: null and ensure CTA/Promo branches
return null when blank), keep using mapNotNull(...).firstOrNull() ?: "" so the
fallback to "" happens only after no non-empty values were found.
- Line 35: Replace the silent use of firstOrNull() on response.data?.experiences
with an explicit uniqueness check: inspect response.data?.experiences (the
collection used to set the experience variable) and if it contains more than one
element fail fast (throw an exception or return a descriptive error/log) instead
of picking the first item; otherwise, when exactly one element exists, assign it
to the experience variable as before. Ensure the check occurs before assigning
to experience and include a clear error message that references the
slug/criteria that produced multiple matches.
- Around line 30-35: Both getContent and listExperiences currently read
response.data without checking GraphQL errors; update the handling after
apolloClient.query(...).execute() (e.g. the ExperienceBySlugQuery call in
getContent and the query in listExperiences) to first inspect response.errors
and handle non-empty errors explicitly: log or surface the errors (include error
messages) and return/throw an appropriate failure instead of silently falling
back to null/empty; only proceed to use response.data (accessing
response.data?.experiences?.firstOrNull() etc.) when response.errors is
null/empty.

In `@mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt`:
- Line 24: The Text composable in MainActivity.kt currently hardcodes visible
text ("Forge Android"); extract this string into Android string resources
(res/values/strings.xml) as a key like forge_android and replace the hardcoded
literal with a resource lookup (e.g., use stringResource(R.string.forge_android)
in the composable or getString(R.string.forge_android) where appropriate), and
add the necessary import (androidx.compose.ui.res.stringResource) so the UI
reads from resources for proper localization.

In `@mobile/android/README.md`:
- Around line 1-60: Run Prettier on mobile/android/README.md to fix the markdown
formatting drift reported by CI: open the README (file name
mobile/android/README.md) and apply the repository's Prettier config (e.g., npx
prettier --write mobile/android/README.md or your IDE formatter) so tables, code
blocks, and line wrapping conform to the project's style; commit the reformatted
README to make forge-ci green.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c6c06d6 and 0f6fd41.

📒 Files selected for processing (13)
  • mobile/android/README.md
  • mobile/android/app/build.gradle.kts
  • mobile/android/app/src/main/AndroidManifest.xml
  • mobile/android/app/src/main/graphql/ExperienceBySlug.graphql
  • mobile/android/app/src/main/graphql/Experiences.graphql
  • mobile/android/app/src/main/graphql/schema.graphqls
  • mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt
  • mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt
  • mobile/android/app/src/main/kotlin/com/forge/mobile/ui/theme/Theme.kt
  • mobile/android/app/src/main/res/values/strings.xml
  • mobile/android/app/src/main/res/values/themes.xml
  • mobile/android/build.gradle.kts
  • mobile/android/gradle.properties

Comment thread mobile/android/app/build.gradle.kts Outdated
Comment thread mobile/android/app/src/main/graphql/schema.graphqls Outdated
Comment thread mobile/android/app/src/main/graphql/schema.graphqls Outdated
Comment thread mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt Outdated
Comment thread mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt Outdated
Comment thread mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt Outdated
Comment thread mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt Outdated
Comment thread mobile/android/README.md Outdated
claude and others added 2 commits March 2, 2026 00:54
- Security: read GRAPHQL_TOKEN from local.properties instead of
  hardcoding an empty string in build.gradle.kts
- Schema: point Apollo directly to apps/cms/schema.graphql (canonical
  source) and delete the committed duplicate schema.graphqls copy
- Apollo: add fieldsOnDisjointTypesMustMerge=false to fix codegen failure
  caused by heading/description/ctaLink having different nullability
  across disjoint union members (ComponentSectionsCta vs
  ComponentSectionsInfoBlocks vs ComponentSectionsPromoBanner)
- GraphQLContentClient: fail fast when >1 experience returned for a slug
  instead of silently using firstOrNull()
- GraphQLContentClient: drop ?: "" fallback in mapNotNull so null
  sections are filtered rather than emitting an empty string
- MainActivity: replace hardcoded "Forge Android" with
  stringResource(R.string.home_title) for i18n parity
- strings.xml: add home_title string resource
- .editorconfig: allow PascalCase for @composable functions (Compose
  naming convention) to fix ktlint violation in Theme.kt
- .gitignore: ignore local.properties and schema.graphqls at both root
  and mobile/android level
- README: update config docs to reflect local.properties token pattern
  and direct schema reference; run Prettier
- ktlintFormat: auto-fix formatting violations in GraphQLContentClient.kt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Both getContent and listExperiences were accessing response.data without
checking response.errors. Apollo Kotlin does not throw on GraphQL errors —
they are surfaced in ApolloResponse.errors while execute() returns normally.
Add an explicit errors check after each execute() call and throw
IllegalStateException with the error messages so callers are not silently
given null/empty results on server-side failures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt (1)

32-35: ⚠️ Potential issue | 🟠 Major

Handle GraphQL response.errors before consuming response.data.

Both query paths currently treat GraphQL errors as empty/null data paths. That can silently hide server contract failures.

Proposed fix
   override suspend fun getContent(
     locale: String,
     slug: String,
   ): MobileContentItem? {
     val response =
       apolloClient
         .query(ExperienceBySlugQuery(slug = slug, locale = com.apollographql.apollo.api.Optional.present(locale)))
         .execute()
+    response.errors?.takeIf { it.isNotEmpty() }?.let { errors ->
+      throw IllegalStateException(
+        "ExperienceBySlug failed: ${errors.joinToString { it.message }}"
+      )
+    }

     val experiences = response.data?.experiences.orEmpty()
@@
   suspend fun listExperiences(
     locale: String,
     page: Int = 1,
     pageSize: Int = 25,
   ): List<MobileContentItem> {
     val response =
       apolloClient
@@
         )
         .execute()
+    response.errors?.takeIf { it.isNotEmpty() }?.let { errors ->
+      throw IllegalStateException(
+        "Experiences failed: ${errors.joinToString { it.message }}"
+      )
+    }

     return response.data?.experiences?.map { experience ->
In Apollo Kotlin 4.x, does query(...).execute() throw on GraphQL errors, or are GraphQL errors returned in ApolloResponse.errors while data may be null/partial?

Also applies to: 80-90

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt`
around lines 32 - 35, Check the ApolloResponse for GraphQL errors before reading
or consuming response.data: after calling
apolloClient.query(ExperienceBySlugQuery(...)).execute() (and the similar query
path around lines 80-90), inspect response.errors (or response.hasErrors()) and
if non-empty throw or return an error result/log with the errors instead of
proceeding to use response.data; update the handling in the functions that call
ExperienceBySlugQuery and the other query invocation to fail fast on GraphQL
errors and only consume response.data when errors is empty and data is non-null.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@mobile/android/README.md`:
- Around line 47-50: The README's claim that the secret is "never compiled into
... the APK artifact" is inaccurate because app/build.gradle.kts injects the
token into BuildConfig via buildConfigField("String", "GRAPHQL_TOKEN", ...),
which gets compiled into the APK; update mobile/android/README.md to state that
the token is kept out of version control (from local.properties) but is included
in the built APK as BuildConfig.GRAPHQL_TOKEN and thus extractable by
decompilation, and suggest alternatives (e.g., fetching from a backend or using
Android Keystore) or note how to override the endpoint in app/build.gradle.kts
if needed.

---

Duplicate comments:
In `@mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt`:
- Around line 32-35: Check the ApolloResponse for GraphQL errors before reading
or consuming response.data: after calling
apolloClient.query(ExperienceBySlugQuery(...)).execute() (and the similar query
path around lines 80-90), inspect response.errors (or response.hasErrors()) and
if non-empty throw or return an error result/log with the errors instead of
proceeding to use response.data; update the handling in the functions that call
ExperienceBySlugQuery and the other query invocation to fail fast on GraphQL
errors and only consume response.data when errors is empty and data is non-null.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 0f6fd41 and 11fb2db.

📒 Files selected for processing (8)
  • .gitignore
  • mobile/android/.editorconfig
  • mobile/android/.gitignore
  • mobile/android/README.md
  • mobile/android/app/build.gradle.kts
  • mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt
  • mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt
  • mobile/android/app/src/main/res/values/strings.xml
🚧 Files skipped from review as they are similar to previous changes (3)
  • mobile/android/app/build.gradle.kts
  • mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt
  • mobile/android/app/src/main/res/values/strings.xml

Comment thread mobile/android/README.md
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt (2)

109-111: Consider implementing Closeable for idiomatic resource management.

Adding Closeable allows usage with Kotlin's use {} or Java's try-with-resources patterns.

♻️ Suggested change
+import java.io.Closeable
+
 class GraphQLContentClient(
   endpoint: String,
   bearerToken: String,
-) : ContentClient {
+) : ContentClient, Closeable {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt`
around lines 109 - 111, Update the GraphQLContentClient class to implement
java.io.Closeable so callers can use Kotlin's use {} or Java try-with-resources;
add the import for java.io.Closeable, change the class declaration to implement
Closeable, and mark the existing fun close() as override (keeping the body that
calls apolloClient.close()) so the type is recognized as a Closeable resource.

34-34: Consider importing Optional to reduce verbosity.

The fully qualified com.apollographql.apollo.api.Optional.present() is used multiple times. A single import would improve readability.

♻️ Suggested import
 import com.apollographql.apollo.network.http.HttpInterceptorChain
+import com.apollographql.apollo.api.Optional
 import com.forge.mobile.graphql.ExperienceBySlugQuery

Then replace usages:

-        .query(ExperienceBySlugQuery(slug = slug, locale = com.apollographql.apollo.api.Optional.present(locale)))
+        .query(ExperienceBySlugQuery(slug = slug, locale = Optional.present(locale)))

Also applies to: 87-89

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt`
at line 34, Add an import for com.apollographql.apollo.api.Optional and replace
fully-qualified calls to com.apollographql.apollo.api.Optional.present(...) with
Optional.present(...) where used (e.g., in the ExperienceBySlugQuery slug/locale
call and the other Optional.present usages around the content fetch methods), so
the code uses the shorter Optional symbol instead of the long package-qualified
name.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt`:
- Around line 109-111: Update the GraphQLContentClient class to implement
java.io.Closeable so callers can use Kotlin's use {} or Java try-with-resources;
add the import for java.io.Closeable, change the class declaration to implement
Closeable, and mark the existing fun close() as override (keeping the body that
calls apolloClient.close()) so the type is recognized as a Closeable resource.
- Line 34: Add an import for com.apollographql.apollo.api.Optional and replace
fully-qualified calls to com.apollographql.apollo.api.Optional.present(...) with
Optional.present(...) where used (e.g., in the ExperienceBySlugQuery slug/locale
call and the other Optional.present usages around the content fetch methods), so
the code uses the shorter Optional symbol instead of the long package-qualified
name.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 11fb2db and 35fa85d.

📒 Files selected for processing (1)
  • mobile/android/app/src/main/kotlin/com/forge/mobile/GraphQLContentClient.kt

claude and others added 2 commits March 2, 2026 01:04
The previous wording said the token is "never compiled into the APK
artifact" which is inaccurate — buildConfigField embeds the value in
BuildConfig and it exists in the APK binary. Clarify that local.properties
keeps the token out of version control, but it is still compiled into the
APK and a short-lived/scoped token should be used.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- .gitignore: keep local.properties + add iOS xcuserdata/Generated ignores from main
- README.md: keep PR's GraphQL integration docs; drop superseded startup-screen note
- build.gradle.kts: remove duplicate buildFeatures/compileOptions/kotlinOptions blocks
  introduced by merge; keep Apollo runtime dependency
- MainActivity.kt: take main's KDoc comments and explicit R import; use startup_title
  string name to match main's convention; remove now-redundant explicit R import
  (ktlint: unnecessary import)
- Theme.kt: take main's KDoc comments for DarkColorScheme, LightColorScheme, ForgeTheme
- strings.xml: align on startup_title name from main

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@up-tandem up-tandem merged commit f76b278 into main Mar 2, 2026
9 of 10 checks passed
@up-tandem up-tandem deleted the android/issue-81-graphql-consumption branch March 2, 2026 01:13
Kneesal pushed a commit to Kneesal/forge that referenced this pull request Mar 9, 2026
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Claude <claude@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(mobile): implement platform-owned GraphQL consumption for native apps

2 participants