Remove Showkase from the project.

This commit is contained in:
Benoit Marty
2026-09-09 15:56:25 +02:00
parent 8e1a34cff8
commit 1ee156f480
20 changed files with 7 additions and 152 deletions
-1
View File
@@ -16,7 +16,6 @@
<w>posthog</w>
<w>rageshake</w>
<w>securebackup</w>
<w>showkase</w>
<w>snackbar</w>
<w>spdx</w>
<w>swipeable</w>
+4 -4
View File
@@ -358,7 +358,8 @@ Some dependency, mainly because they are not shared can be declared in `build.gr
We have 3 tests frameworks in place, and this should be sufficient to guarantee a good code coverage and limit regressions hopefully:
- Maestro to test the global usage of the application. See the related [documentation](../.maestro/README.md).
- Combination of [Showkase](https://github.com/airbnb/Showkase) and [Paparazzi](https://github.com/cashapp/paparazzi), to test UI pixel perfect. To add test,
- Combination of [Paparazzi](https://github.com/cashapp/paparazzi) and
[ComposablePreviewScanner](https://github.com/sergio-sastre/ComposablePreviewScanner), to test UI pixel perfect. To add test,
just add `@Preview` for the composable you are adding. See the related [documentation](screenshot_testing.md) and see in the template the
file [TemplateView.kt](../features/template/src/main/kotlin/io/element/android/features/template/TemplateView.kt). We create PreviewParam classes to provide
different states. See for instance the
@@ -449,9 +450,8 @@ number at the bottom 7 times. After tapping, a new "Developer options" entry wil
at the bottom of the list.
The developer options include feature flags, notification/push history, Element call
customization, Rust SDK log levels, per-feature tracing toggles, Showkase to debug UI
components, rageshake controls, app crash controls, cache details/controls, persistent
storage maintenance tasks.
customization, Rust SDK log levels, per-feature tracing toggles, rageshake controls, app
crash controls, cache details/controls, persistent storage maintenance tasks.
Keywords: Developer settings, developer mode
@@ -94,7 +94,6 @@ dependencies {
implementation(libs.androidx.datastore.preferences)
implementation(libs.serialization.json)
api(projects.features.preferences.api)
implementation(libs.showkase)
implementation(platform(libs.network.okhttp.bom))
implementation(libs.network.okhttp)
@@ -8,10 +8,8 @@
package io.element.android.features.preferences.impl.developer
import androidx.activity.compose.LocalActivity
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.airbnb.android.showkase.models.Showkase
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
@@ -20,7 +18,6 @@ import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.preferences.api.ExtraDeveloperOptionsRenderer
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.designsystem.showkase.getBrowserIntent
import io.element.android.libraries.di.SessionScope
@ContributesNode(SessionScope::class)
@@ -47,17 +44,10 @@ class DeveloperSettingsNode(
@Composable
override fun View(modifier: Modifier) {
val activity = requireNotNull(LocalActivity.current)
fun openShowkase() {
val intent = Showkase.getBrowserIntent(activity)
activity.startActivity(intent)
}
val state = presenter.present()
DeveloperSettingsView(
state = state,
modifier = modifier,
onOpenShowkase = ::openShowkase,
onPushHistoryClick = callback::navigateToPushHistory,
onBackClick = callback::onDone,
extraOptions = { extraDeveloperOptionsRenderer.Render(Modifier) },
@@ -44,7 +44,6 @@ import io.mhssn.colorpicker.ColorPickerType
@Composable
fun DeveloperSettingsView(
state: DeveloperSettingsState,
onOpenShowkase: () -> Unit,
onPushHistoryClick: () -> Unit,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
@@ -84,7 +83,6 @@ fun DeveloperSettingsView(
// Note: this is OK to hardcode strings in this debug screen.
AppDeveloperSettingsView(
state = state.appDeveloperSettingsState,
onOpenShowkase = onOpenShowkase,
)
SessionCategory(deviceId = state.deviceId)
NotificationCategory(
@@ -255,7 +253,6 @@ internal fun DeveloperSettingsViewPreview(
) = ElementPreview {
DeveloperSettingsView(
state = state,
onOpenShowkase = {},
onPushHistoryClick = {},
onBackClick = {},
)
@@ -7,10 +7,8 @@
package io.element.android.features.preferences.impl.developer.appsettings
import androidx.activity.compose.LocalActivity
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.airbnb.android.showkase.models.Showkase
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
@@ -21,7 +19,6 @@ import io.element.android.annotations.ContributesNode
import io.element.android.features.preferences.api.ExtraDeveloperOptionsRenderer
import io.element.android.features.preferences.api.PreferencesEntryPoint
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.designsystem.showkase.getBrowserIntent
@ContributesNode(AppScope::class)
@AssistedInject
@@ -35,17 +32,10 @@ class AppDeveloperSettingsNode(
@Composable
override fun View(modifier: Modifier) {
val activity = requireNotNull(LocalActivity.current)
fun openShowkase() {
val intent = Showkase.getBrowserIntent(activity)
activity.startActivity(intent)
}
val state = presenter.present()
AppDeveloperSettingsPage(
state = state,
modifier = modifier,
onOpenShowkase = ::openShowkase,
onBackClick = callback::onDone,
extraOptions = { extraDeveloperOptionsRenderer.Render(Modifier) },
)
@@ -21,7 +21,6 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@Composable
fun AppDeveloperSettingsPage(
state: AppDeveloperSettingsState,
onOpenShowkase: () -> Unit,
onBackClick: () -> Unit,
modifier: Modifier = Modifier,
extraOptions: @Composable () -> Unit = {},
@@ -38,7 +37,6 @@ fun AppDeveloperSettingsPage(
) {
AppDeveloperSettingsView(
state = state,
onOpenShowkase = onOpenShowkase,
modifier = Modifier.padding(top = 8.dp)
)
extraOptions()
@@ -50,7 +48,6 @@ fun AppDeveloperSettingsPage(
internal fun AppDeveloperSettingsPagePreview() = ElementPreview {
AppDeveloperSettingsPage(
state = anAppDeveloperSettingsState(),
onOpenShowkase = {},
onBackClick = {},
)
}
@@ -42,7 +42,6 @@ import kotlinx.collections.immutable.toImmutableList
@Composable
fun AppDeveloperSettingsView(
state: AppDeveloperSettingsState,
onOpenShowkase: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
@@ -82,14 +81,6 @@ fun AppDeveloperSettingsView(
)
}
}
PreferenceCategory(title = "Showkase") {
ListItem(
content = {
Text("Open Showkase browser")
},
onClick = onOpenShowkase
)
}
RageshakePreferencesView(
state = state.rageshakeState,
)
@@ -186,6 +177,5 @@ internal fun AppDeveloperSettingsViewPreview(
) = ElementPreview {
AppDeveloperSettingsView(
state = state,
onOpenShowkase = {},
)
}
@@ -70,21 +70,6 @@ class DeveloperSettingsViewTest : RobolectricTest() {
eventsRecorder.assertSingle(DeveloperSettingsEvent.OpenPushRules)
}
@Config(qualifiers = "h2000dp")
@Test
fun `clicking on open showkase invokes the expected callback`() = runAndroidComposeUiTest {
val eventsRecorder = EventsRecorder<DeveloperSettingsEvent>(expectEvents = false)
ensureCalledOnce {
setDeveloperSettingsView(
state = aDeveloperSettingsState(
eventSink = eventsRecorder
),
onOpenShowkase = it
)
onNodeWithText("Open Showkase browser").performClick()
}
}
@Config(qualifiers = "h2400dp")
@Test
fun `clicking on clear cache emits the expected event`() = runAndroidComposeUiTest {
@@ -101,14 +86,12 @@ class DeveloperSettingsViewTest : RobolectricTest() {
private fun AndroidComposeUiTest<ComponentActivity>.setDeveloperSettingsView(
state: DeveloperSettingsState,
onOpenShowkase: () -> Unit = EnsureNeverCalled(),
onPushHistoryClick: () -> Unit = EnsureNeverCalled(),
onBackClick: () -> Unit = EnsureNeverCalled()
) {
setContent {
DeveloperSettingsView(
state = state,
onOpenShowkase = onOpenShowkase,
onPushHistoryClick = onPushHistoryClick,
onBackClick = onBackClick,
)
@@ -64,21 +64,6 @@ class AppDeveloperSettingsPageTest : RobolectricTest() {
eventsRecorder.assertSingle(AppDeveloperSettingsEvent.SetCustomElementCallBaseUrl("https://call.element.dev"))
}
@Config(qualifiers = "h2000dp")
@Test
fun `clicking on open showkase invokes the expected callback`() = runAndroidComposeUiTest {
val eventsRecorder = EventsRecorder<AppDeveloperSettingsEvent>(expectEvents = false)
ensureCalledOnce {
setAppDeveloperSettingsView(
state = anAppDeveloperSettingsState(
eventSink = eventsRecorder
),
onOpenShowkase = it
)
onNodeWithText("Open Showkase browser").performClick()
}
}
@Config(qualifiers = "h1024dp")
@Test
fun `clicking on log level emits the expected event`() = runAndroidComposeUiTest {
@@ -96,13 +81,11 @@ class AppDeveloperSettingsPageTest : RobolectricTest() {
private fun AndroidComposeUiTest<ComponentActivity>.setAppDeveloperSettingsView(
state: AppDeveloperSettingsState,
onOpenShowkase: () -> Unit = EnsureNeverCalled(),
onBackClick: () -> Unit = EnsureNeverCalled(),
) {
setContent {
AppDeveloperSettingsPage(
state = state,
onOpenShowkase = onOpenShowkase,
onBackClick = onBackClick,
)
}
-4
View File
@@ -40,8 +40,6 @@ serialization_json = "1.11.0"
#other
coil = "3.6.1"
# Rollback to 1.0.4, 1.0.5 has this issue: https://github.com/airbnb/Showkase/issues/420
showkase = "1.0.5"
# There is some custom logic in `RootFlowNode` that may break because it reuses some Appyx internal APIs.
# When upgrading this version, check state restoration still works fine.
appyx = "1.7.1"
@@ -198,8 +196,6 @@ coil_test = { module = "io.coil-kt.coil3:coil-test", version.ref = "coil" }
datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "datetime" }
serialization_json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialization_json" }
kotlinx_collections_immutable = "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.5.2"
showkase = { module = "com.airbnb.android:showkase", version.ref = "showkase" }
showkase_processor = { module = "com.airbnb.android:showkase-processor", version.ref = "showkase" }
jsoup = "org.jsoup:jsoup:1.23.2"
appyx_core = { module = "com.bumble.appyx:core", version.ref = "appyx" }
molecule-runtime = "app.cash.molecule:molecule-runtime:2.2.0"
-1
View File
@@ -22,7 +22,6 @@ android {
}
dependencies {
implementation(libs.showkase)
testCommonDependencies(libs)
testImplementation(libs.test.roborazzi)
testImplementation(libs.test.roborazzi.compose)
@@ -1,15 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.compound.showkase
import com.airbnb.android.showkase.annotation.ShowkaseRoot
import com.airbnb.android.showkase.annotation.ShowkaseRootModule
@ShowkaseRoot
class CompoundShowkaseRootModule : ShowkaseRootModule
@@ -16,19 +16,15 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.LineHeightStyle
import androidx.compose.ui.unit.em
import androidx.compose.ui.unit.sp
import com.airbnb.android.showkase.annotation.ShowkaseTypography
import io.element.android.compound.tokens.generated.TypographyTokens
// 32px (Material) vs 34px, it's the closest one
@ShowkaseTypography(name = "M3 Headline Large", group = "Compound")
internal val compoundHeadingXlRegular = TypographyTokens.fontHeadingXlRegular
// both are 28px
@ShowkaseTypography(name = "M3 Headline Medium", group = "Compound")
internal val compoundHeadingLgRegular = TypographyTokens.fontHeadingLgRegular
// These are the default M3 values, but we're setting them manually so an update in M3 doesn't break our designs
@ShowkaseTypography(name = "M3 Headline Small", group = "Compound")
internal val defaultHeadlineSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
@@ -40,39 +36,27 @@ internal val defaultHeadlineSmall = TextStyle(
)
// 22px (Material) vs 20px, it's the closest one
@ShowkaseTypography(name = "M3 Title Large", group = "Compound")
internal val compoundHeadingMdRegular = TypographyTokens.fontHeadingMdRegular
// 16px both
@ShowkaseTypography(name = "M3 Title Medium", group = "Compound")
internal val compoundBodyLgMedium = TypographyTokens.fontBodyLgMedium
// 14px both
@ShowkaseTypography(name = "M3 Title Small", group = "Compound")
internal val compoundBodyMdMedium = TypographyTokens.fontBodyMdMedium
// 16px both
@ShowkaseTypography(name = "M3 Body Large", group = "Compound")
internal val compoundBodyLgRegular = TypographyTokens.fontBodyLgRegular
// 14px both
@ShowkaseTypography(name = "M3 Body Medium", group = "Compound")
internal val compoundBodyMdRegular = TypographyTokens.fontBodyMdRegular
// 12px both
@ShowkaseTypography(name = "M3 Body Small", group = "Compound")
internal val compoundBodySmRegular = TypographyTokens.fontBodySmRegular
// 14px both, Title Small uses the same token so we have to declare it twice
@ShowkaseTypography(name = "M3 Label Large", group = "Compound")
internal val compoundBodyMdMedium_LabelLarge = TypographyTokens.fontBodyMdMedium
// 12px both
@ShowkaseTypography(name = "M3 Label Medium", group = "Compound")
internal val compoundBodySmMedium = TypographyTokens.fontBodySmMedium
// 11px both
@ShowkaseTypography(name = "M3 Label Small", group = "Compound")
internal val compoundBodyXsMedium = TypographyTokens.fontBodyXsMedium
internal val compoundTypography = Typography(
@@ -88,7 +72,7 @@ internal val compoundTypography = Typography(
bodyLarge = compoundBodyLgRegular,
bodyMedium = compoundBodyMdRegular,
bodySmall = compoundBodySmRegular,
labelLarge = compoundBodyMdMedium_LabelLarge,
labelLarge = compoundBodyMdMedium,
labelMedium = compoundBodySmMedium,
labelSmall = compoundBodyXsMedium,
)
-10
View File
@@ -10,7 +10,6 @@ import extension.testCommonDependencies
plugins {
id("io.element.android-compose-library")
alias(libs.plugins.ksp)
id("kotlin-parcelize")
}
@@ -20,12 +19,6 @@ android {
buildFeatures {
buildConfig = true
}
buildTypes {
getByName("release") {
consumerProguardFiles("consumer-rules.keep")
}
}
}
dependencies {
@@ -43,8 +36,5 @@ dependencies {
implementation(projects.libraries.testtags)
implementation(projects.libraries.uiStrings)
ksp(libs.showkase.processor)
implementation(libs.showkase)
testCommonDependencies(libs)
}
@@ -1,5 +0,0 @@
# Showkase generates this class, and Showkase's ShowkaseBrowserActivity loads it reflectively with
# Class.forName(...).getDeclaredConstructor().newInstance(), so its constructor must be kept too.
-keep class io.element.android.libraries.designsystem.showkase.DesignSystemShowkaseRootModuleCodegen {
<init>();
}
@@ -14,8 +14,8 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
/**
* Showkase does not take into account the `fontScale` parameter of the Preview annotation, so alter the
* LocalDensity in the CompositionLocalProvider.
* Render the content at the given font scale, by altering the `LocalDensity` in the
* CompositionLocalProvider. Useful to preview a Composable at several font scales.
*/
@Composable
fun WithFontScale(fontScale: Float, content: @Composable () -> Unit) {
@@ -1,15 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2022-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.showkase
import com.airbnb.android.showkase.annotation.ShowkaseRoot
import com.airbnb.android.showkase.annotation.ShowkaseRootModule
@ShowkaseRoot
class DesignSystemShowkaseRootModule : ShowkaseRootModule
@@ -107,13 +107,8 @@ fun Project.setupKover() {
// Exclude generated classes.
"*_Module",
"*_AssistedFactory",
"com.airbnb.android.showkase*",
"io.element.android.libraries.designsystem.showkase.*",
"*ComposableSingletons$*",
"*BuildConfig",
// Generated by Showkase
"*Ioelementandroid*PreviewKt$*",
"*Ioelementandroid*PreviewKt",
// Other
// We do not cover Nodes (normally covered by maestro, but code coverage is not computed with maestro)
"*Node",
-2
View File
@@ -40,8 +40,6 @@ dependencies {
)
}
implementation(libs.showkase)
// TODO There is a Resources.NotFoundException maybe due to the mipmap, even if we have
// `testOptions { unitTests.isIncludeAndroidResources = true }` in the app build.gradle.kts file
// implementation(projects.app)