Add ability to EnterpriseService to override theme colors

This commit is contained in:
Benoit Marty 2025-01-31 16:50:01 +01:00
parent 79293e1e9d
commit 468ef0f7fc
13 changed files with 51 additions and 6 deletions

View file

@ -61,7 +61,10 @@ class MainActivity : NodeActivity() {
@Composable @Composable
private fun MainContent(appBindings: AppBindings) { private fun MainContent(appBindings: AppBindings) {
val migrationState = appBindings.migrationEntryPoint().present() val migrationState = appBindings.migrationEntryPoint().present()
ElementThemeApp(appBindings.preferencesStore()) { ElementThemeApp(
appPreferencesStore = appBindings.preferencesStore(),
enterpriseService = appBindings.enterpriseService(),
) {
CompositionLocalProvider( CompositionLocalProvider(
LocalSnackbarDispatcher provides appBindings.snackbarDispatcher(), LocalSnackbarDispatcher provides appBindings.snackbarDispatcher(),
LocalUriHandler provides SafeUriHandler(this), LocalUriHandler provides SafeUriHandler(this),
@ -69,8 +72,8 @@ class MainActivity : NodeActivity() {
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.background(MaterialTheme.colorScheme.background), .background(MaterialTheme.colorScheme.background),
) { ) {
if (migrationState.migrationAction.isSuccess()) { if (migrationState.migrationAction.isSuccess()) {
MainNodeHost() MainNodeHost()

View file

@ -9,6 +9,7 @@ package io.element.android.x.di
import com.squareup.anvil.annotations.ContributesTo import com.squareup.anvil.annotations.ContributesTo
import io.element.android.features.api.MigrationEntryPoint import io.element.android.features.api.MigrationEntryPoint
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.lockscreen.api.LockScreenEntryPoint import io.element.android.features.lockscreen.api.LockScreenEntryPoint
import io.element.android.features.lockscreen.api.LockScreenService import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.rageshake.api.reporter.BugReporter import io.element.android.features.rageshake.api.reporter.BugReporter
@ -35,4 +36,6 @@ interface AppBindings {
fun lockScreenEntryPoint(): LockScreenEntryPoint fun lockScreenEntryPoint(): LockScreenEntryPoint
fun analyticsService(): AnalyticsService fun analyticsService(): AnalyticsService
fun enterpriseService(): EnterpriseService
} }

View file

@ -29,6 +29,7 @@ setupAnvil()
dependencies { dependencies {
implementation(projects.appconfig) implementation(projects.appconfig)
implementation(projects.features.enterprise.api)
implementation(projects.libraries.architecture) implementation(projects.libraries.architecture)
implementation(projects.libraries.core) implementation(projects.libraries.core)
implementation(projects.libraries.designsystem) implementation(projects.libraries.designsystem)

View file

@ -44,6 +44,7 @@ import io.element.android.features.call.impl.pip.PictureInPictureState
import io.element.android.features.call.impl.pip.PipView import io.element.android.features.call.impl.pip.PipView
import io.element.android.features.call.impl.services.CallForegroundService import io.element.android.features.call.impl.services.CallForegroundService
import io.element.android.features.call.impl.utils.CallIntentDataParser import io.element.android.features.call.impl.utils.CallIntentDataParser
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.log.logger.LoggerTag import io.element.android.libraries.core.log.logger.LoggerTag
@ -61,6 +62,7 @@ class ElementCallActivity :
@Inject lateinit var callIntentDataParser: CallIntentDataParser @Inject lateinit var callIntentDataParser: CallIntentDataParser
@Inject lateinit var presenterFactory: CallScreenPresenter.Factory @Inject lateinit var presenterFactory: CallScreenPresenter.Factory
@Inject lateinit var appPreferencesStore: AppPreferencesStore @Inject lateinit var appPreferencesStore: AppPreferencesStore
@Inject lateinit var enterpriseService: EnterpriseService
@Inject lateinit var pictureInPicturePresenter: PictureInPicturePresenter @Inject lateinit var pictureInPicturePresenter: PictureInPicturePresenter
private lateinit var presenter: Presenter<CallScreenState> private lateinit var presenter: Presenter<CallScreenState>
@ -109,7 +111,10 @@ class ElementCallActivity :
setContent { setContent {
val pipState = pictureInPicturePresenter.present() val pipState = pictureInPicturePresenter.present()
ListenToAndroidEvents(pipState) ListenToAndroidEvents(pipState)
ElementThemeApp(appPreferencesStore) { ElementThemeApp(
appPreferencesStore = appPreferencesStore,
enterpriseService = enterpriseService,
) {
val state = presenter.present() val state = presenter.present()
eventSink = state.eventSink eventSink = state.eventSink
LaunchedEffect(state.isCallActive, state.isInWidgetMode) { LaunchedEffect(state.isCallActive, state.isInWidgetMode) {

View file

@ -19,6 +19,7 @@ import io.element.android.features.call.impl.di.CallBindings
import io.element.android.features.call.impl.notifications.CallNotificationData import io.element.android.features.call.impl.notifications.CallNotificationData
import io.element.android.features.call.impl.utils.ActiveCallManager import io.element.android.features.call.impl.utils.ActiveCallManager
import io.element.android.features.call.impl.utils.CallState import io.element.android.features.call.impl.utils.CallState
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.architecture.bindings import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.designsystem.theme.ElementThemeApp import io.element.android.libraries.designsystem.theme.ElementThemeApp
import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.preferences.api.store.AppPreferencesStore
@ -47,6 +48,9 @@ class IncomingCallActivity : AppCompatActivity() {
@Inject @Inject
lateinit var appPreferencesStore: AppPreferencesStore lateinit var appPreferencesStore: AppPreferencesStore
@Inject
lateinit var enterpriseService: EnterpriseService
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -64,7 +68,10 @@ class IncomingCallActivity : AppCompatActivity() {
val notificationData = intent?.let { IntentCompat.getParcelableExtra(it, EXTRA_NOTIFICATION_DATA, CallNotificationData::class.java) } val notificationData = intent?.let { IntentCompat.getParcelableExtra(it, EXTRA_NOTIFICATION_DATA, CallNotificationData::class.java) }
if (notificationData != null) { if (notificationData != null) {
setContent { setContent {
ElementThemeApp(appPreferencesStore) { ElementThemeApp(
appPreferencesStore = appPreferencesStore,
enterpriseService = enterpriseService,
) {
IncomingCallScreen( IncomingCallScreen(
notificationData = notificationData, notificationData = notificationData,
onAnswer = ::onAnswer, onAnswer = ::onAnswer,

View file

@ -13,6 +13,7 @@ android {
} }
dependencies { dependencies {
api(libs.compound)
implementation(projects.libraries.architecture) implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrix.api)
} }

View file

@ -7,9 +7,13 @@
package io.element.android.features.enterprise.api package io.element.android.features.enterprise.api
import io.element.android.compound.tokens.generated.SemanticColors
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
interface EnterpriseService { interface EnterpriseService {
val isEnterpriseBuild: Boolean val isEnterpriseBuild: Boolean
suspend fun isEnterpriseUser(sessionId: SessionId): Boolean suspend fun isEnterpriseUser(sessionId: SessionId): Boolean
fun semanticColorsLight(): SemanticColors
fun semanticColorsDark(): SemanticColors
} }

View file

@ -21,6 +21,7 @@ dependencies {
api(projects.features.enterprise.api) api(projects.features.enterprise.api)
implementation(projects.libraries.architecture) implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrix.api)
api(libs.compound)
testImplementation(libs.coroutines.test) testImplementation(libs.coroutines.test)
testImplementation(libs.test.junit) testImplementation(libs.test.junit)

View file

@ -8,6 +8,9 @@
package io.element.android.features.enterprise.impl package io.element.android.features.enterprise.impl
import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.compound.tokens.generated.SemanticColors
import io.element.android.compound.tokens.generated.compoundColorsDark
import io.element.android.compound.tokens.generated.compoundColorsLight
import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.SessionId
@ -18,4 +21,8 @@ class DefaultEnterpriseService @Inject constructor() : EnterpriseService {
override val isEnterpriseBuild = false override val isEnterpriseBuild = false
override suspend fun isEnterpriseUser(sessionId: SessionId) = false override suspend fun isEnterpriseUser(sessionId: SessionId) = false
override fun semanticColorsLight(): SemanticColors = compoundColorsLight
override fun semanticColorsDark(): SemanticColors = compoundColorsDark
} }

View file

@ -21,6 +21,7 @@ setupAnvil()
dependencies { dependencies {
api(projects.features.lockscreen.api) api(projects.features.lockscreen.api)
implementation(projects.appconfig) implementation(projects.appconfig)
implementation(projects.features.enterprise.api)
implementation(projects.libraries.core) implementation(projects.libraries.core)
implementation(projects.libraries.architecture) implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrix.api)

View file

@ -16,6 +16,7 @@ import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.lockscreen.api.LockScreenLockState import io.element.android.features.lockscreen.api.LockScreenLockState
import io.element.android.features.lockscreen.api.LockScreenService import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter import io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter
@ -38,13 +39,17 @@ class PinUnlockActivity : AppCompatActivity() {
@Inject lateinit var presenter: PinUnlockPresenter @Inject lateinit var presenter: PinUnlockPresenter
@Inject lateinit var lockScreenService: LockScreenService @Inject lateinit var lockScreenService: LockScreenService
@Inject lateinit var appPreferencesStore: AppPreferencesStore @Inject lateinit var appPreferencesStore: AppPreferencesStore
@Inject lateinit var enterpriseService: EnterpriseService
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge() enableEdgeToEdge()
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
bindings<PinUnlockBindings>().inject(this) bindings<PinUnlockBindings>().inject(this)
setContent { setContent {
ElementThemeApp(appPreferencesStore) { ElementThemeApp(
appPreferencesStore = appPreferencesStore,
enterpriseService = enterpriseService,
) {
val state = presenter.present() val state = presenter.present()
val isDark = ElementTheme.isLightTheme.not() val isDark = ElementTheme.isLightTheme.not()
PinUnlockView( PinUnlockView(

View file

@ -31,6 +31,7 @@ android {
implementation(libs.androidx.compose.material3.adaptive) implementation(libs.androidx.compose.material3.adaptive)
implementation(libs.coil.compose) implementation(libs.coil.compose)
implementation(libs.vanniktech.blurhash) implementation(libs.vanniktech.blurhash)
implementation(projects.features.enterprise.api)
implementation(projects.libraries.architecture) implementation(projects.libraries.architecture)
implementation(projects.libraries.preferences.api) implementation(projects.libraries.preferences.api)
implementation(projects.libraries.testtags) implementation(projects.libraries.testtags)

View file

@ -17,6 +17,7 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme import io.element.android.compound.theme.Theme
import io.element.android.compound.theme.isDark import io.element.android.compound.theme.isDark
import io.element.android.compound.theme.mapToTheme import io.element.android.compound.theme.mapToTheme
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.preferences.api.store.AppPreferencesStore import io.element.android.libraries.preferences.api.store.AppPreferencesStore
/** /**
@ -29,6 +30,7 @@ import io.element.android.libraries.preferences.api.store.AppPreferencesStore
@Composable @Composable
fun ElementThemeApp( fun ElementThemeApp(
appPreferencesStore: AppPreferencesStore, appPreferencesStore: AppPreferencesStore,
enterpriseService: EnterpriseService,
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
val theme by remember { val theme by remember {
@ -44,8 +46,12 @@ fun ElementThemeApp(
} }
) )
} }
val compoundLight = remember { enterpriseService.semanticColorsLight() }
val compoundDark = remember { enterpriseService.semanticColorsDark() }
ElementTheme( ElementTheme(
darkTheme = theme.isDark(), darkTheme = theme.isDark(),
content = content, content = content,
compoundLight = compoundLight,
compoundDark = compoundDark,
) )
} }