Merge pull request #4378 from element-hq/feature/bma/customSuperButton

Be able to correctly render the UI with other colors.
This commit is contained in:
Benoit Marty
2025-03-11 09:26:54 +01:00
committed by GitHub
20 changed files with 131 additions and 37 deletions

View File

@@ -64,6 +64,7 @@ class MainActivity : NodeActivity() {
ElementThemeApp(
appPreferencesStore = appBindings.preferencesStore(),
enterpriseService = appBindings.enterpriseService(),
buildMeta = appBindings.buildMeta()
) {
CompositionLocalProvider(
LocalSnackbarDispatcher provides appBindings.snackbarDispatcher(),

View File

@@ -13,6 +13,7 @@ import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.lockscreen.api.LockScreenEntryPoint
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.rageshake.api.reporter.BugReporter
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.tracing.TracingService
@@ -38,4 +39,6 @@ interface AppBindings {
fun analyticsService(): AnalyticsService
fun enterpriseService(): EnterpriseService
fun buildMeta(): BuildMeta
}

View File

@@ -48,6 +48,7 @@ import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.log.logger.LoggerTag
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.designsystem.theme.ElementThemeApp
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import timber.log.Timber
@@ -64,6 +65,7 @@ class ElementCallActivity :
@Inject lateinit var appPreferencesStore: AppPreferencesStore
@Inject lateinit var enterpriseService: EnterpriseService
@Inject lateinit var pictureInPicturePresenter: PictureInPicturePresenter
@Inject lateinit var buildMeta: BuildMeta
private lateinit var presenter: Presenter<CallScreenState>
@@ -114,6 +116,7 @@ class ElementCallActivity :
ElementThemeApp(
appPreferencesStore = appPreferencesStore,
enterpriseService = enterpriseService,
buildMeta = buildMeta,
) {
val state = presenter.present()
eventSink = state.eventSink

View File

@@ -21,6 +21,7 @@ import io.element.android.features.call.impl.utils.ActiveCallManager
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.core.meta.BuildMeta
import io.element.android.libraries.designsystem.theme.ElementThemeApp
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import kotlinx.coroutines.flow.filter
@@ -51,6 +52,9 @@ class IncomingCallActivity : AppCompatActivity() {
@Inject
lateinit var enterpriseService: EnterpriseService
@Inject
lateinit var buildMeta: BuildMeta
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -71,6 +75,7 @@ class IncomingCallActivity : AppCompatActivity() {
ElementThemeApp(
appPreferencesStore = appPreferencesStore,
enterpriseService = enterpriseService,
buildMeta = buildMeta,
) {
IncomingCallScreen(
notificationData = notificationData,

View File

@@ -22,6 +22,7 @@ import io.element.android.features.lockscreen.impl.unlock.PinUnlockPresenter
import io.element.android.features.lockscreen.impl.unlock.PinUnlockView
import io.element.android.features.lockscreen.impl.unlock.di.PinUnlockBindings
import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.designsystem.theme.ElementThemeApp
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
import kotlinx.coroutines.launch
@@ -38,6 +39,7 @@ class PinUnlockActivity : AppCompatActivity() {
@Inject lateinit var lockScreenService: LockScreenService
@Inject lateinit var appPreferencesStore: AppPreferencesStore
@Inject lateinit var enterpriseService: EnterpriseService
@Inject lateinit var buildMeta: BuildMeta
override fun onCreate(savedInstanceState: Bundle?) {
enableEdgeToEdge()
@@ -47,6 +49,7 @@ class PinUnlockActivity : AppCompatActivity() {
ElementThemeApp(
appPreferencesStore = appPreferencesStore,
enterpriseService = enterpriseService,
buildMeta = buildMeta,
) {
val state = presenter.present()
PinUnlockView(

View File

@@ -8,6 +8,8 @@
package io.element.android.features.messages.impl.timeline.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@@ -28,7 +30,10 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
import io.element.android.features.messages.impl.timeline.model.event.TimelineItemStateContent
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionEvent
import io.element.android.features.messages.impl.timeline.protection.TimelineProtectionState
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.toPx
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
import io.element.android.libraries.designsystem.theme.highlightedMessageBackgroundColor
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UserId
@@ -171,8 +176,13 @@ private fun Modifier.focusedEvent(
focusedEventOffset: Dp
): Modifier {
val highlightedLineColor = ElementTheme.colors.textActionAccent
val gradientFirstColor = if (LocalBuildMeta.current.isEnterpriseBuild) {
ElementTheme.colors.textActionAccent.copy(alpha = 0.125f)
} else {
ElementTheme.colors.highlightedMessageBackgroundColor
}
val gradientColors = listOf(
ElementTheme.colors.highlightedMessageBackgroundColor,
gradientFirstColor,
ElementTheme.colors.bgCanvasDefault,
)
val verticalOffset = focusedEventOffset.toPx()
@@ -196,3 +206,15 @@ private fun Modifier.focusedEvent(
}
}.padding(top = 4.dp)
}
@PreviewsDayNight
@Composable
internal fun FocusedEventPreview() = ElementPreview {
Box(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
.height(160.dp)
.focusedEvent(0.dp),
)
}

View File

@@ -37,13 +37,13 @@ internal fun TimelineItemReadMarkerView(
Text(
text = stringResource(id = R.string.screen_room_timeline_read_marker_title).uppercase(),
style = ElementTheme.typography.fontBodySmMedium,
color = ElementTheme.colors.textSecondary,
color = ElementTheme.colors.textActionAccent,
)
HorizontalDivider(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 2.dp),
color = ElementTheme.colors.borderInteractivePrimary,
color = ElementTheme.colors.textActionAccent,
)
}
}

View File

@@ -27,6 +27,7 @@ import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.geometry.center
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.LinearGradientShader
import androidx.compose.ui.graphics.RadialGradientShader
@@ -36,10 +37,12 @@ import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import io.element.android.compound.annotations.CoreColorToken
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.compound.tokens.generated.internal.LightColorTokens
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
import io.element.android.libraries.designsystem.theme.components.Icon
@OptIn(CoreColorToken::class)
@@ -50,6 +53,16 @@ fun GradientFloatingActionButton(
shape: Shape = RoundedCornerShape(25),
content: @Composable () -> Unit,
) {
val color1 = if (LocalBuildMeta.current.isEnterpriseBuild) {
ElementTheme.colors.textActionAccent
} else {
LightColorTokens.colorGreen700
}
val color2 = if (LocalBuildMeta.current.isEnterpriseBuild) {
ElementTheme.colors.textActionAccent
} else {
LightColorTokens.colorBlue900
}
val linearShaderBrush = remember {
object : ShaderBrush() {
override fun createShader(size: Size): Shader {
@@ -57,8 +70,8 @@ fun GradientFloatingActionButton(
from = Offset(size.width, size.height),
to = Offset(size.width, 0f),
colors = listOf(
LightColorTokens.colorBlue900,
LightColorTokens.colorGreen700,
color2,
color1,
),
)
}
@@ -71,8 +84,8 @@ fun GradientFloatingActionButton(
center = size.center,
radius = size.width / 2,
colors = listOf(
LightColorTokens.colorGreen700,
LightColorTokens.colorBlue900,
color1,
color2,
)
)
}
@@ -85,8 +98,8 @@ fun GradientFloatingActionButton(
.graphicsLayer(shape = shape, clip = false)
.clip(shape)
.drawBehind {
drawRect(brush = radialShaderBrush, alpha = 0.4f)
drawRect(brush = linearShaderBrush)
drawRect(brush = radialShaderBrush, alpha = 0.4f, blendMode = BlendMode.Overlay)
}
.clickable(
enabled = true,

View File

@@ -42,6 +42,7 @@ import io.element.android.compound.tokens.generated.internal.DarkColorTokens
import io.element.android.compound.tokens.generated.internal.LightColorTokens
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.LocalBuildMeta
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.HorizontalDivider
import io.element.android.libraries.designsystem.theme.components.lowHorizontalPaddingValue
@@ -66,17 +67,24 @@ fun SuperButton(
}
}
val isLightTheme = ElementTheme.isLightTheme
val colors = remember(isLightTheme) {
if (isLightTheme) {
listOf(
LightColorTokens.colorBlue900,
LightColorTokens.colorGreen1100,
)
} else {
listOf(
DarkColorTokens.colorBlue900,
DarkColorTokens.colorGreen1100,
)
val colors = if (LocalBuildMeta.current.isEnterpriseBuild) {
listOf(
ElementTheme.colors.textActionAccent,
ElementTheme.colors.textActionAccent,
)
} else {
remember(isLightTheme) {
if (isLightTheme) {
listOf(
LightColorTokens.colorBlue900,
LightColorTokens.colorGreen1100,
)
} else {
listOf(
DarkColorTokens.colorBlue900,
DarkColorTokens.colorGreen1100,
)
}
}
}

View File

@@ -9,17 +9,40 @@ package io.element.android.libraries.designsystem.theme
import androidx.appcompat.app.AppCompatDelegate
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.compound.theme.isDark
import io.element.android.compound.theme.mapToTheme
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
val LocalBuildMeta = staticCompositionLocalOf {
BuildMeta(
isDebuggable = true,
buildType = BuildType.DEBUG,
applicationName = "MyApp",
productionApplicationName = "MyAppProd",
desktopApplicationName = "MyAppDesktop",
applicationId = "AppId",
isEnterpriseBuild = false,
lowPrivacyLoggingEnabled = false,
versionName = "aVersion",
versionCode = 123,
gitRevision = "aRevision",
gitBranchName = "aBranch",
flavorDescription = "aFlavor",
flavorShortDescription = "aFlavorShort",
)
}
/**
* Theme to use for all the regular screens of the application.
* Will manage the light / dark theme based on the user preference.
@@ -31,6 +54,7 @@ import io.element.android.libraries.preferences.api.store.AppPreferencesStore
fun ElementThemeApp(
appPreferencesStore: AppPreferencesStore,
enterpriseService: EnterpriseService,
buildMeta: BuildMeta,
content: @Composable () -> Unit,
) {
val theme by remember {
@@ -48,10 +72,14 @@ fun ElementThemeApp(
}
val compoundLight = remember { enterpriseService.semanticColorsLight() }
val compoundDark = remember { enterpriseService.semanticColorsDark() }
ElementTheme(
darkTheme = theme.isDark(),
content = content,
compoundLight = compoundLight,
compoundDark = compoundDark,
)
CompositionLocalProvider(
LocalBuildMeta provides buildMeta,
) {
ElementTheme(
darkTheme = theme.isDark(),
content = content,
compoundLight = compoundLight,
compoundDark = compoundDark,
)
}
}

View File

@@ -66,6 +66,7 @@ class KonsistPreviewTest {
"CallScreenPipViewPreview",
"ColorAliasesPreview",
"DefaultRoomListTopBarWithIndicatorPreview",
"FocusedEventPreview",
"GradientFloatingActionButtonCircleShapePreview",
"IconsCompoundPreview",
"IconsOtherPreview",

View File

@@ -229,6 +229,7 @@ Compose:
- LocalRoomMemberProfilesCache
- LocalMentionSpanTheme
- LocalAnalyticsService
- LocalBuildMeta
CompositionLocalNaming:
active: true
ContentEmitterReturningValues: