feat(healthchat): drop Element links, labs, bug reports and location sharing

Bloom gradient fades the brand blue instead of Compound's green.
This commit is contained in:
Sedat Qaja
2026-10-20 13:39:31 +02:00
parent 9df5d95732
commit 67dadb4571
9 changed files with 64 additions and 25 deletions
@@ -12,6 +12,7 @@ import androidx.compose.ui.graphics.Color
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.compound.colors.SemanticColorsLightDark
import io.element.android.compound.tokens.generated.SemanticColors
import io.element.android.features.enterprise.api.BugReportUrl
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.androidutils.json.JsonProvider
@@ -64,7 +65,7 @@ class DefaultEnterpriseService(
}
override fun semanticColorsFlow(sessionId: SessionId?): Flow<SemanticColorsLightDark> {
return flowOf(SemanticColorsLightDark.default)
return flowOf(healthChatSemanticColors)
}
override fun firebasePushGateway(): String? = null
@@ -77,6 +78,27 @@ class DefaultEnterpriseService(
override fun getNoisyNotificationChannelId(sessionId: SessionId): String? = null
}
/** HealthChat brand blue, the launcher background colour. */
private val healthChatBrandBlue = Color(0xFF12325C)
/**
* The subtle gradient (home screen bloom, highlighted timeline item) fades the brand blue out at the
* opacities Compound uses for its green stops; stop 6 stays transparent. Every other token, including the
* accent colours, is Compound's default: only the bloom changes.
*/
private fun SemanticColors.withHealthChatBloom() = copy(
gradientSubtleStop1 = healthChatBrandBlue.copy(alpha = 0.41f),
gradientSubtleStop2 = healthChatBrandBlue.copy(alpha = 0.23f),
gradientSubtleStop3 = healthChatBrandBlue.copy(alpha = 0.11f),
gradientSubtleStop4 = healthChatBrandBlue.copy(alpha = 0.06f),
gradientSubtleStop5 = healthChatBrandBlue.copy(alpha = 0.03f),
)
internal val healthChatSemanticColors = SemanticColorsLightDark(
light = SemanticColorsLightDark.default.light.withHealthChatBloom(),
dark = SemanticColorsLightDark.default.dark.withHealthChatBloom(),
)
/**
* HealthChat is locked to its own homeserver: this is the only account provider users can sign in to.
*/
@@ -8,6 +8,7 @@
package io.element.android.features.enterprise.impl
import androidx.compose.ui.graphics.Color
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.compound.colors.SemanticColorsLightDark
@@ -23,6 +24,7 @@ import io.element.android.libraries.matrix.test.accountprovider.anAccountProvide
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
@@ -61,11 +63,22 @@ class DefaultEnterpriseServiceTest {
val defaultEnterpriseService = createDefaultEnterpriseService()
defaultEnterpriseService.semanticColorsFlow(null).test {
val initialState = awaitItem()
assertThat(initialState).isEqualTo(SemanticColorsLightDark.default)
assertThat(initialState).isEqualTo(healthChatSemanticColors)
awaitComplete()
}
}
@Test
fun `semanticColorsFlow only changes the subtle gradient to the HealthChat blue`() = runTest {
val colors = createDefaultEnterpriseService().semanticColorsFlow(null).first()
val default = SemanticColorsLightDark.default
assertThat(colors.light.gradientSubtleStop1).isEqualTo(Color(0xFF12325C).copy(alpha = 0.41f))
assertThat(colors.dark.gradientSubtleStop5).isEqualTo(Color(0xFF12325C).copy(alpha = 0.03f))
assertThat(colors.light.gradientSubtleStop6).isEqualTo(default.light.gradientSubtleStop6)
assertThat(colors.light.bgAccentRest).isEqualTo(default.light.bgAccentRest)
assertThat(colors.dark.bgAccentRest).isEqualTo(default.dark.bgAccentRest)
}
@Test
fun `brandColorsFlow always emits null`() = runTest {
val defaultEnterpriseService = createDefaultEnterpriseService()
@@ -81,7 +94,7 @@ class DefaultEnterpriseServiceTest {
val defaultEnterpriseService = createDefaultEnterpriseService()
defaultEnterpriseService.semanticColorsFlow(A_SESSION_ID).test {
val initialState = awaitItem()
assertThat(initialState).isEqualTo(SemanticColorsLightDark.default)
assertThat(initialState).isEqualTo(healthChatSemanticColors)
awaitComplete()
}
}
@@ -17,6 +17,7 @@ import io.element.android.features.location.api.buildTimeMapTilerConfig
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.di.annotations.SessionCoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flow
@@ -35,4 +36,7 @@ class DefaultLocationService(
started = SharingStarted.Eagerly,
initialValue = buildTimeMapTilerConfig(),
)
// HealthChat fork: location sharing is not offered, even if the homeserver advertises a map provider.
override fun isServiceAvailable(): StateFlow<Boolean> = MutableStateFlow(false)
}
@@ -29,7 +29,7 @@ class DefaultLocationServiceTest {
)
runCurrent()
assertThat(locationService.mapTilerConfig.value).isEqualTo(buildTimeMapTilerConfig())
assertThat(locationService.isServiceAvailable().value).isEqualTo(buildTimeMapTilerConfig() != null)
assertThat(locationService.isServiceAvailable().value).isFalse()
}
@Test
@@ -39,7 +39,7 @@ class DefaultLocationServiceTest {
)
runCurrent()
assertThat(locationService.mapTilerConfig.value).isEqualTo(buildTimeMapTilerConfig())
assertThat(locationService.isServiceAvailable().value).isEqualTo(buildTimeMapTilerConfig() != null)
assertThat(locationService.isServiceAvailable().value).isFalse()
}
@Test
@@ -50,7 +50,8 @@ class DefaultLocationServiceTest {
)
runCurrent()
assertThat(locationService.mapTilerConfig.value).isEqualTo(config)
assertThat(locationService.isServiceAvailable().value).isTrue()
// HealthChat fork: the service is never available, even with a homeserver config.
assertThat(locationService.isServiceAvailable().value).isFalse()
}
private fun TestScope.createDefaultLocationService(
@@ -131,7 +131,8 @@ class PreferencesRootPresenter(
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
val hasAnalyticsProviders = remember { analyticsService.getAvailableAnalyticsProviders().isNotEmpty() }
val showLabsItem = remember { featureFlagService.getAvailableFeatures(isInLabs = true).isNotEmpty() }
// HealthChat fork: upstream experiments are not offered to HealthChat users.
val showLabsItem = false
val showDeveloperSettings by showDeveloperSettingsProvider.showDeveloperSettings.collectAsState()
@@ -198,7 +198,8 @@ class PreferencesRootPresenterTest {
}
),
).test {
assertThat(awaitItem().showLabsItem).isTrue()
// HealthChat fork: labs are never offered, whatever the feature flags say.
assertThat(awaitItem().showLabsItem).isFalse()
cancelAndIgnoreRemainingEvents()
}
}