feat(android): scaffold buildable app shell with Compose startup screen#88
feat(android): scaffold buildable app shell with Compose startup screen#88
Conversation
Add AndroidManifest, MainActivity with Material3 Compose UI, string/theme resources, Compose BOM and compiler config. Downgrade Kotlin to 1.9.24 for Compose compiler compatibility. Document local build commands in README. Resolves #80 (Android portion) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WalkthroughEstablishes a buildable Android app shell by configuring Gradle build settings (Jetpack Compose, Java 17, Kotlin compiler), adding manifest and activity wiring, defining theme and string resources, and documenting build prerequisites and commands. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
mobile/android/app/build.gradle.kts (1)
13-13:⚠️ Potential issue | 🟠 Major
targetSdk = 34blocks Google Play submission.Google Play has required all new app submissions and updates to target API level 35 since August 31, 2025. The current setting violates this mandatory requirement. Change
targetSdk = 35to comply and also unlockenableEdgeToEdge()enforcement (see theMainActivitycomment).🔧 Fix
- targetSdk = 34 + targetSdk = 35🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mobile/android/app/build.gradle.kts` at line 13, The build.gradle.kts currently sets targetSdk = 34 which prevents Google Play submission; update the value to targetSdk = 35 in the Android module so the app targets API level 35, then re-enable edge-to-edge enforcement referenced by enableEdgeToEdge() (and remove the temporary bypass noted in MainActivity) so UI behavior matches the new target; verify no other gradle properties or manifest settings conflict with API 35 after changing targetSdk.
🧹 Nitpick comments (6)
mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt (1)
16-16: AddenableEdgeToEdge()beforesetContent {}.
enableEdgeToEdge()is the standard call for new Compose activities and becomes mandatory whentargetSdkis bumped to 35. Adding it now avoids a required follow-up.♻️ Proposed fix
+import androidx.activity.enableEdgeToEdge ... override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + enableEdgeToEdge() setContent {🤖 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/MainActivity.kt` at line 16, Add a call to enableEdgeToEdge() in MainActivity.onCreate before the setContent { ... } invocation to opt into edge-to-edge window insets handling; locate the onCreate method in MainActivity and insert enableEdgeToEdge() just after super.onCreate(savedInstanceState) and before setContent so Compose uses edge-to-edge behaviour (this prevents future breakage when targetSdk is bumped).mobile/android/app/src/main/res/values/themes.xml (1)
3-3: Consider usingTheme.MaterialComponents.DayNight.NoActionBaras the base theme.
android:Theme.Material.Light.NoActionBaris the legacy platform theme. Sincematerial3is already on the classpath (via BOM),Theme.MaterialComponents.DayNight.NoActionBaris a more idiomatic base for a Material3 Compose app and automatically handles some window/inset system-bar defaults more gracefully.♻️ Proposed change
- <style name="Theme.Forge" parent="android:Theme.Material.Light.NoActionBar" /> + <style name="Theme.Forge" parent="Theme.MaterialComponents.DayNight.NoActionBar" />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mobile/android/app/src/main/res/values/themes.xml` at line 3, Update the app theme style "Theme.Forge" to use the Material Components DayNight base by changing its parent from "android:Theme.Material.Light.NoActionBar" to "Theme.MaterialComponents.DayNight.NoActionBar" so the app leverages Material3/BOM behavior and better system-bar/window defaults; locate the <style name="Theme.Forge" parent="..."> entry and replace the parent attribute accordingly.mobile/android/app/build.gradle.kts (2)
22-24:composeOptionsblock is only needed for Kotlin < 2.0 — remove when upgrading Kotlin.As of Kotlin 2.0, the Compose compiler is managed alongside the Kotlin compiler. In versions lower than Kotlin 2.0, consult the Compose to Kotlin Compatibility Map to identify a compatible compiler version. If the project is upgraded to Kotlin 2.0+ (suggested in the root
build.gradle.ktscomment), this block andkotlinOptions.jvmTargetcan both be removed and replaced withkotlin { jvmToolchain(17) }.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mobile/android/app/build.gradle.kts` around lines 22 - 24, The composeOptions block setting kotlinCompilerExtensionVersion is no longer needed once Kotlin is upgraded to 2.0+; remove the composeOptions block (the kotlinCompilerExtensionVersion assignment) and also remove kotlinOptions.jvmTarget, and replace them with the Kotlin toolchain configuration by adding kotlin { jvmToolchain(17) } in the relevant Gradle Kotlin DSL configuration (where kotlinOptions and composeOptions currently appear) so the Compose compiler is managed by the Kotlin compiler.
37-37: Update Compose BOM to the latest stable release2026.01.01.The current BOM
2024.09.02is ~17 months old. The latest stable release was published on January 29, 2026.♻️ Proposed update
- implementation(platform("androidx.compose:compose-bom:2024.09.02")) + implementation(platform("androidx.compose:compose-bom:2026.01.01"))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mobile/android/app/build.gradle.kts` at line 37, Update the Compose BOM version string used in the build script: locate the implementation(platform("androidx.compose:compose-bom:2024.09.02")) entry and change the BOM coordinate to "androidx.compose:compose-bom:2026.01.01" so the project uses the latest stable Compose BOM; ensure you update any dependency constraints or lockfiles if present and re-sync the Gradle project to validate compatibility.mobile/android/app/src/main/AndroidManifest.xml (1)
9-12:android:themeon the<activity>is redundant when it matches the<application>theme.Activities inherit the
<application>theme by default. Declaring the same@style/Theme.Forgeon both is harmless but adds noise.♻️ Proposed cleanup
<activity android:name=".MainActivity" - android:exported="true" - android:theme="@style/Theme.Forge"> + android:exported="true">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mobile/android/app/src/main/AndroidManifest.xml` around lines 9 - 12, Remove the redundant android:theme attribute from the <activity> entry for MainActivity since it duplicates the application theme; locate the <activity android:name=".MainActivity"> element in the AndroidManifest and delete the android:theme="@style/Theme.Forge" attribute so the activity inherits the application theme by default.mobile/android/build.gradle.kts (1)
3-3: Update to Kotlin 2.3.10 to adopt the merged Compose compiler plugin and remove version friction.Compose compiler
1.5.14targets Kotlin1.9.24, so the current pairing is correct. However, the Compose compiler has been merged into the Kotlin repository since Kotlin 2.0.0, so it ships simultaneously with Kotlin and is always compatible with the same Kotlin version. Staying on Kotlin 1.9.x in 2026 creates unnecessary migration debt—Kotlin 2.3.10 is the current stable release as of February 2026.Upgrading to Kotlin
2.3.10also lets you dropcomposeOptions.kotlinCompilerExtensionVersioninapp/build.gradle.kts(see comment there) and replace this plugin with the neworg.jetbrains.kotlin.plugin.composeGradle plugin:♻️ Kotlin 2.3.10 migration sketch
plugins { id("com.android.application") version "8.5.2" apply false - id("org.jetbrains.kotlin.android") version "1.9.24" apply false + id("org.jetbrains.kotlin.android") version "2.3.10" apply false + id("org.jetbrains.kotlin.plugin.compose") version "2.3.10" apply false id("org.jlleitschuh.gradle.ktlint") version "12.1.1" }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mobile/android/build.gradle.kts` at line 3, Update the top-level Kotlin plugin from id("org.jetbrains.kotlin.android") version "1.9.24" to use Kotlin 2.3.10 and the new Compose plugin identifier: replace id("org.jetbrains.kotlin.android") version "1.9.24" apply false with id("org.jetbrains.kotlin.plugin.compose") version "2.3.10" apply false; then remove the now-unnecessary composeOptions.kotlinCompilerExtensionVersion entry from app/build.gradle.kts and ensure module-level builds apply the new org.jetbrains.kotlin.plugin.compose plugin where Compose is used so the Compose compiler is provided by the Kotlin 2.3.10 runtime.
🤖 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/src/main/AndroidManifest.xml`:
- Around line 4-8: The <application> element is missing launcher icon attributes
so the app shows the default AOSP icon; add android:icon and android:roundIcon
attributes (e.g., android:icon="@mipmap/ic_launcher" and
android:roundIcon="@mipmap/ic_launcher_round") to the <application> tag and
create corresponding adaptive icon resources (mipmap/ic_launcher.xml and
mipmap/ic_launcher_round.xml plus foreground/background drawables in
mipmap-anydpi-v26 and legacy PNGs in appropriate mipmap folders) so the launcher
uses your adaptive icons; update resource names in AndroidManifest.xml to match
the created files.
In `@mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt`:
- Around line 27-30: Replace the hardcoded Text("Forge Android") in
MainActivity.kt with a string resource: add a new entry (e.g., <string
name="splash_label">Forge Android</string>) to your strings.xml, then change the
Text composable to use stringResource(R.string.splash_label) (or update
R.string.app_name if you prefer to reuse it); update imports to include
androidx.compose.ui.res.stringResource if needed so the Text uses the localized
resource instead of a hardcoded literal.
---
Outside diff comments:
In `@mobile/android/app/build.gradle.kts`:
- Line 13: The build.gradle.kts currently sets targetSdk = 34 which prevents
Google Play submission; update the value to targetSdk = 35 in the Android module
so the app targets API level 35, then re-enable edge-to-edge enforcement
referenced by enableEdgeToEdge() (and remove the temporary bypass noted in
MainActivity) so UI behavior matches the new target; verify no other gradle
properties or manifest settings conflict with API 35 after changing targetSdk.
---
Nitpick comments:
In `@mobile/android/app/build.gradle.kts`:
- Around line 22-24: The composeOptions block setting
kotlinCompilerExtensionVersion is no longer needed once Kotlin is upgraded to
2.0+; remove the composeOptions block (the kotlinCompilerExtensionVersion
assignment) and also remove kotlinOptions.jvmTarget, and replace them with the
Kotlin toolchain configuration by adding kotlin { jvmToolchain(17) } in the
relevant Gradle Kotlin DSL configuration (where kotlinOptions and composeOptions
currently appear) so the Compose compiler is managed by the Kotlin compiler.
- Line 37: Update the Compose BOM version string used in the build script:
locate the implementation(platform("androidx.compose:compose-bom:2024.09.02"))
entry and change the BOM coordinate to "androidx.compose:compose-bom:2026.01.01"
so the project uses the latest stable Compose BOM; ensure you update any
dependency constraints or lockfiles if present and re-sync the Gradle project to
validate compatibility.
In `@mobile/android/app/src/main/AndroidManifest.xml`:
- Around line 9-12: Remove the redundant android:theme attribute from the
<activity> entry for MainActivity since it duplicates the application theme;
locate the <activity android:name=".MainActivity"> element in the
AndroidManifest and delete the android:theme="@style/Theme.Forge" attribute so
the activity inherits the application theme by default.
In `@mobile/android/app/src/main/kotlin/com/forge/mobile/MainActivity.kt`:
- Line 16: Add a call to enableEdgeToEdge() in MainActivity.onCreate before the
setContent { ... } invocation to opt into edge-to-edge window insets handling;
locate the onCreate method in MainActivity and insert enableEdgeToEdge() just
after super.onCreate(savedInstanceState) and before setContent so Compose uses
edge-to-edge behaviour (this prevents future breakage when targetSdk is bumped).
In `@mobile/android/app/src/main/res/values/themes.xml`:
- Line 3: Update the app theme style "Theme.Forge" to use the Material
Components DayNight base by changing its parent from
"android:Theme.Material.Light.NoActionBar" to
"Theme.MaterialComponents.DayNight.NoActionBar" so the app leverages
Material3/BOM behavior and better system-bar/window defaults; locate the <style
name="Theme.Forge" parent="..."> entry and replace the parent attribute
accordingly.
In `@mobile/android/build.gradle.kts`:
- Line 3: Update the top-level Kotlin plugin from
id("org.jetbrains.kotlin.android") version "1.9.24" to use Kotlin 2.3.10 and the
new Compose plugin identifier: replace id("org.jetbrains.kotlin.android")
version "1.9.24" apply false with id("org.jetbrains.kotlin.plugin.compose")
version "2.3.10" apply false; then remove the now-unnecessary
composeOptions.kotlinCompilerExtensionVersion entry from app/build.gradle.kts
and ensure module-level builds apply the new org.jetbrains.kotlin.plugin.compose
plugin where Compose is used so the Compose compiler is provided by the Kotlin
2.3.10 runtime.
| <application | ||
| android:allowBackup="false" | ||
| android:label="@string/app_name" | ||
| android:supportsRtl="true" | ||
| android:theme="@style/Theme.Forge"> |
There was a problem hiding this comment.
Missing android:icon and android:roundIcon — the launcher will show the default AOSP icon.
Add adaptive icon resources and declare them on the <application> element to complete the app shell:
<application
android:allowBackup="false"
+ android:icon="@mipmap/ic_launcher"
+ android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.Forge">📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <application | |
| android:allowBackup="false" | |
| android:label="@string/app_name" | |
| android:supportsRtl="true" | |
| android:theme="@style/Theme.Forge"> | |
| <application | |
| android:allowBackup="false" | |
| android:icon="@mipmap/ic_launcher" | |
| android:roundIcon="@mipmap/ic_launcher_round" | |
| android:label="@string/app_name" | |
| android:supportsRtl="true" | |
| android:theme="@style/Theme.Forge"> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@mobile/android/app/src/main/AndroidManifest.xml` around lines 4 - 8, The
<application> element is missing launcher icon attributes so the app shows the
default AOSP icon; add android:icon and android:roundIcon attributes (e.g.,
android:icon="@mipmap/ic_launcher" and
android:roundIcon="@mipmap/ic_launcher_round") to the <application> tag and
create corresponding adaptive icon resources (mipmap/ic_launcher.xml and
mipmap/ic_launcher_round.xml plus foreground/background drawables in
mipmap-anydpi-v26 and legacy PNGs in appropriate mipmap folders) so the launcher
uses your adaptive icons; update resource names in AndroidManifest.xml to match
the created files.
| Text( | ||
| text = "Forge Android", | ||
| style = MaterialTheme.typography.headlineMedium, | ||
| ) |
There was a problem hiding this comment.
Hardcoded splash text "Forge Android" should be a string resource.
R.string.app_name currently holds "Forge" (not "Forge Android"), so either add a dedicated resource (e.g., R.string.splash_label) or align app_name with the desired display text.
♻️ Proposed fix (after adding splash_label to strings.xml)
In strings.xml:
+ <string name="splash_label">Forge Android</string>In MainActivity.kt:
+import androidx.compose.ui.res.stringResource
...
Text(
- text = "Forge Android",
+ text = stringResource(R.string.splash_label),
style = MaterialTheme.typography.headlineMedium,
)🤖 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/MainActivity.kt` around
lines 27 - 30, Replace the hardcoded Text("Forge Android") in MainActivity.kt
with a string resource: add a new entry (e.g., <string name="splash_label">Forge
Android</string>) to your strings.xml, then change the Text composable to use
stringResource(R.string.splash_label) (or update R.string.app_name if you prefer
to reuse it); update imports to include androidx.compose.ui.res.stringResource
if needed so the Text uses the localized resource instead of a hardcoded
literal.
Summary
assembleDebug,installDebug,ktlintCheck) in READMETest plan
./gradlew :app:assembleDebugbuilds successfully./gradlew ktlintCheckpasses with no violationsResolves #80 (Android portion)
🤖 Generated with Claude Code
Summary by CodeRabbit
Documentation
New Features
Chores