From 007e8a3100af7a240972f947583c1b0f5553e605 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 11 Dec 2025 16:17:27 +0100 Subject: [PATCH 1/2] feat(android): Add Showkase component browser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add Airbnb's Showkase library (v1.0.5) to provide a component browser for all Compose previews. Accessible via a button in Settings screen in debug builds only. - Add Showkase dependencies to gradle version catalog - Configure debug-only implementation via build variants - Create ShowkaseLauncher with debug/release variants - Add "Component Browser" button in Settings (debug builds only) - Configure KSP to skip private previews and run debug-only The Component Browser button appears under a new "Developer" section in the Settings screen, only visible in debug builds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- android/app/build.gradle.kts | 10 ++++++++-- .../hackernews/ShowkaseLauncher.kt | 12 +++++++++++ .../hackernews/ShowkaseRootModule.kt | 7 +++++++ .../features/settings/SettingsScreen.kt | 20 +++++++++++++++++++ .../hackernews/ShowkaseLauncher.kt | 11 ++++++++++ android/gradle/libs.versions.toml | 5 +++++ 6 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 android/app/src/debug/java/com/emergetools/hackernews/ShowkaseLauncher.kt create mode 100644 android/app/src/debug/java/com/emergetools/hackernews/ShowkaseRootModule.kt create mode 100644 android/app/src/release/java/com/emergetools/hackernews/ShowkaseLauncher.kt diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index 350ec8f3..f81ef59a 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -90,6 +90,7 @@ android { ksp { arg("room.generateKotlin", "true") + arg("skipPrivatePreviews", "true") } emerge { @@ -117,8 +118,8 @@ sentry { } distribution { - //enabled = providers.environmentVariable("GITHUB_ACTIONS").isPresent - //updateSdkVariants.add("beta") + enabled = providers.environmentVariable("GITHUB_ACTIONS").isPresent + updateSdkVariants.add("beta") } vcsInfo { @@ -178,4 +179,9 @@ dependencies { debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) + // Showkase - Component Browser (Debug only) + debugImplementation(libs.showkase) + implementation(libs.showkase.annotation) + kspDebug(libs.showkase.processor) + } diff --git a/android/app/src/debug/java/com/emergetools/hackernews/ShowkaseLauncher.kt b/android/app/src/debug/java/com/emergetools/hackernews/ShowkaseLauncher.kt new file mode 100644 index 00000000..686bd59c --- /dev/null +++ b/android/app/src/debug/java/com/emergetools/hackernews/ShowkaseLauncher.kt @@ -0,0 +1,12 @@ +package com.emergetools.hackernews + +import android.content.Context +import com.airbnb.android.showkase.models.Showkase + +object ShowkaseLauncher { + fun launch(context: Context) { + context.startActivity(Showkase.getBrowserIntent(context)) + } + + const val isAvailable = true +} diff --git a/android/app/src/debug/java/com/emergetools/hackernews/ShowkaseRootModule.kt b/android/app/src/debug/java/com/emergetools/hackernews/ShowkaseRootModule.kt new file mode 100644 index 00000000..135024ca --- /dev/null +++ b/android/app/src/debug/java/com/emergetools/hackernews/ShowkaseRootModule.kt @@ -0,0 +1,7 @@ +package com.emergetools.hackernews + +import com.airbnb.android.showkase.annotation.ShowkaseRoot +import com.airbnb.android.showkase.annotation.ShowkaseRootModule + +@ShowkaseRoot +class HackerNewsShowkaseRoot : ShowkaseRootModule diff --git a/android/app/src/main/java/com/emergetools/hackernews/features/settings/SettingsScreen.kt b/android/app/src/main/java/com/emergetools/hackernews/features/settings/SettingsScreen.kt index 3c05ca13..826b637f 100644 --- a/android/app/src/main/java/com/emergetools/hackernews/features/settings/SettingsScreen.kt +++ b/android/app/src/main/java/com/emergetools/hackernews/features/settings/SettingsScreen.kt @@ -15,6 +15,7 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Lock import androidx.compose.material.icons.rounded.Warning +import androidx.compose.ui.platform.LocalContext import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.NavigationBar @@ -34,6 +35,7 @@ import androidx.compose.ui.tooling.preview.Devices import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.emergetools.hackernews.R +import com.emergetools.hackernews.ShowkaseLauncher import com.emergetools.hackernews.features.settings.components.BuiltByCard import com.emergetools.hackernews.features.settings.components.LoginCard import com.emergetools.hackernews.features.settings.components.SettingsCard @@ -182,6 +184,24 @@ fun SettingsScreen( ) { navigation(SettingsNavigation.GoToSettingsLink("https://www.emergetools.com/HackerNewsPrivacyPolicy.html")) } + if (ShowkaseLauncher.isAvailable) { + Spacer(modifier = Modifier.height(8.dp)) + SettingsSectionLabel("Developer") + val context = LocalContext.current + SettingsCard( + leadingIcon = { + Icon( + modifier = Modifier.width(12.dp), + painter = painterResource(R.drawable.ic_settings), + tint = MaterialTheme.colorScheme.primary, + contentDescription = "Component Browser" + ) + }, + label = "Component Browser" + ) { + ShowkaseLauncher.launch(context) + } + } } } } diff --git a/android/app/src/release/java/com/emergetools/hackernews/ShowkaseLauncher.kt b/android/app/src/release/java/com/emergetools/hackernews/ShowkaseLauncher.kt new file mode 100644 index 00000000..fc93de01 --- /dev/null +++ b/android/app/src/release/java/com/emergetools/hackernews/ShowkaseLauncher.kt @@ -0,0 +1,11 @@ +package com.emergetools.hackernews + +import android.content.Context + +object ShowkaseLauncher { + fun launch(context: Context) { + // No-op in release builds + } + + const val isAvailable = false +} diff --git a/android/gradle/libs.versions.toml b/android/gradle/libs.versions.toml index df218585..a32b4fc2 100644 --- a/android/gradle/libs.versions.toml +++ b/android/gradle/libs.versions.toml @@ -29,6 +29,7 @@ composeBom = "2025.09.00" uiTestJunit4Android = "1.10.0" uiautomator = "2.3.0" benchmarkMacroJunit4 = "1.4.1" +showkase = "1.0.5" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -75,6 +76,10 @@ androidx-ui-test-junit4-android = { group = "androidx.compose.ui", name = "ui-te androidx-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" } androidx-benchmark-macro-junit4 = { group = "androidx.benchmark", name = "benchmark-macro-junit4", version.ref = "benchmarkMacroJunit4" } +showkase = { group = "com.airbnb.android", name = "showkase", version.ref = "showkase" } +showkase-annotation = { group = "com.airbnb.android", name = "showkase-annotation", version.ref = "showkase" } +showkase-processor = { group = "com.airbnb.android", name = "showkase-processor", version.ref = "showkase" } + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } From 373846897f5e0fc2b017ebebe7c2e5ea9c3d7aa9 Mon Sep 17 00:00:00 2001 From: Nelson Osacky Date: Thu, 11 Dec 2025 16:42:36 +0100 Subject: [PATCH 2/2] chore(android): Remove Showkase comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- android/app/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index f81ef59a..925813b7 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -179,7 +179,6 @@ dependencies { debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - // Showkase - Component Browser (Debug only) debugImplementation(libs.showkase) implementation(libs.showkase.annotation) kspDebug(libs.showkase.processor)