Remove unused composable and cleanup colors (#5000)

* Remove unused BigCheckmark

* Change fun to val and extend SemanticColors

* Add preview for mentions in the context of the timeline.

* Update screenshots

---------

Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
Benoit Marty 2025-07-09 14:37:32 +02:00 committed by GitHub
commit 8fec3986b4
11 changed files with 148 additions and 97 deletions

View file

@ -219,7 +219,7 @@ private fun NameAndTimestampRow(
style = ElementTheme.typography.fontBodyLgMedium, style = ElementTheme.typography.fontBodyLgMedium,
text = name ?: stringResource(id = CommonStrings.common_no_room_name), text = name ?: stringResource(id = CommonStrings.common_no_room_name),
fontStyle = FontStyle.Italic.takeIf { name == null }, fontStyle = FontStyle.Italic.takeIf { name == null },
color = ElementTheme.roomListRoomName(), color = ElementTheme.colors.roomListRoomName,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )
@ -230,7 +230,7 @@ private fun NameAndTimestampRow(
color = if (isHighlighted) { color = if (isHighlighted) {
ElementTheme.colors.unreadIndicator ElementTheme.colors.unreadIndicator
} else { } else {
ElementTheme.roomListRoomMessageDate() ElementTheme.colors.roomListRoomMessageDate
}, },
) )
} }
@ -253,7 +253,7 @@ private fun InviteSubtitle(
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
style = ElementTheme.typography.fontBodyMdRegular, style = ElementTheme.typography.fontBodyMdRegular,
color = ElementTheme.roomListRoomMessage(), color = ElementTheme.colors.roomListRoomMessage,
modifier = modifier, modifier = modifier,
) )
} }
@ -277,7 +277,7 @@ private fun MessagePreviewAndIndicatorRow(
Text( Text(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
text = annotatedMessagePreview, text = annotatedMessagePreview,
color = ElementTheme.roomListRoomMessage(), color = ElementTheme.colors.roomListRoomMessage,
style = ElementTheme.typography.fontBodyMdRegular, style = ElementTheme.typography.fontBodyMdRegular,
minLines = 2, minLines = 2,
maxLines = 2, maxLines = 2,
@ -325,7 +325,7 @@ private fun InviteNameAndIndicatorRow(
style = ElementTheme.typography.fontBodyLgMedium, style = ElementTheme.typography.fontBodyLgMedium,
text = name ?: stringResource(id = CommonStrings.common_no_room_name), text = name ?: stringResource(id = CommonStrings.common_no_room_name),
fontStyle = FontStyle.Italic.takeIf { name == null }, fontStyle = FontStyle.Italic.takeIf { name == null },
color = ElementTheme.roomListRoomName(), color = ElementTheme.colors.roomListRoomName,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis overflow = TextOverflow.Ellipsis
) )

View file

@ -1,67 +0,0 @@
/*
* Copyright 2024 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.components
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.bigCheckmarkBorderColor
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.ui.strings.CommonStrings
/**
* Compound component that displays a big checkmark centered in a rounded square.
*
* @param modifier the modifier to apply to this layout
*/
@Composable
fun BigCheckmark(
modifier: Modifier = Modifier,
) {
Surface(
modifier = modifier.size(120.dp),
shape = RoundedCornerShape(14.dp),
color = ElementTheme.colors.bgCanvasDefault,
border = BorderStroke(1.dp, ElementTheme.colors.bigCheckmarkBorderColor),
shadowElevation = 4.dp,
) {
Box(contentAlignment = Alignment.Center) {
Icon(
modifier = Modifier.size(72.dp),
tint = ElementTheme.colors.iconSuccessPrimary,
imageVector = CompoundIcons.CheckCircleSolid(),
contentDescription = stringResource(CommonStrings.common_success)
)
}
}
}
@PreviewsDayNight
@Composable
internal fun BigCheckmarkPreview() {
ElementPreview {
Box(
modifier = Modifier.padding(10.dp),
contentAlignment = Alignment.Center,
) {
BigCheckmark()
}
}
}

View file

@ -22,14 +22,14 @@ import kotlinx.collections.immutable.persistentMapOf
/** /**
* Room list. * Room list.
*/ */
@Composable val SemanticColors.roomListRoomName
fun ElementTheme.roomListRoomName() = colors.textPrimary get() = textPrimary
@Composable val SemanticColors.roomListRoomMessage
fun ElementTheme.roomListRoomMessage() = colors.textSecondary get() = textSecondary
@Composable val SemanticColors.roomListRoomMessageDate
fun ElementTheme.roomListRoomMessageDate() = colors.textSecondary get() = textSecondary
val SemanticColors.unreadIndicator val SemanticColors.unreadIndicator
get() = iconAccentTertiary get() = iconAccentTertiary
@ -66,10 +66,6 @@ val SemanticColors.temporaryColorBgSpecial
val SemanticColors.pinDigitBg val SemanticColors.pinDigitBg
get() = if (isLight) LightColorTokens.colorGray300 else DarkColorTokens.colorGray400 get() = if (isLight) LightColorTokens.colorGray300 else DarkColorTokens.colorGray400
@OptIn(CoreColorToken::class)
val SemanticColors.bigCheckmarkBorderColor
get() = if (isLight) LightColorTokens.colorGray400 else DarkColorTokens.colorGray400
@OptIn(CoreColorToken::class) @OptIn(CoreColorToken::class)
val SemanticColors.pinnedMessageBannerIndicator val SemanticColors.pinnedMessageBannerIndicator
get() = if (isLight) LightColorTokens.colorAlphaGray600 else DarkColorTokens.colorAlphaGray600 get() = if (isLight) LightColorTokens.colorAlphaGray600 else DarkColorTokens.colorAlphaGray600
@ -85,16 +81,15 @@ internal fun ColorAliasesPreview() = ElementPreview {
backgroundColor = Color.Black, backgroundColor = Color.Black,
foregroundColor = Color.White, foregroundColor = Color.White,
colors = persistentMapOf( colors = persistentMapOf(
"roomListRoomName" to ElementTheme.roomListRoomName(), "roomListRoomName" to ElementTheme.colors.roomListRoomName,
"roomListRoomMessage" to ElementTheme.roomListRoomMessage(), "roomListRoomMessage" to ElementTheme.colors.roomListRoomMessage,
"roomListRoomMessageDate" to ElementTheme.roomListRoomMessageDate(), "roomListRoomMessageDate" to ElementTheme.colors.roomListRoomMessageDate,
"unreadIndicator" to ElementTheme.colors.unreadIndicator, "unreadIndicator" to ElementTheme.colors.unreadIndicator,
"placeholderBackground" to ElementTheme.colors.placeholderBackground, "placeholderBackground" to ElementTheme.colors.placeholderBackground,
"messageFromMeBackground" to ElementTheme.colors.messageFromMeBackground, "messageFromMeBackground" to ElementTheme.colors.messageFromMeBackground,
"messageFromOtherBackground" to ElementTheme.colors.messageFromOtherBackground, "messageFromOtherBackground" to ElementTheme.colors.messageFromOtherBackground,
"progressIndicatorTrackColor" to ElementTheme.colors.progressIndicatorTrackColor, "progressIndicatorTrackColor" to ElementTheme.colors.progressIndicatorTrackColor,
"temporaryColorBgSpecial" to ElementTheme.colors.temporaryColorBgSpecial, "temporaryColorBgSpecial" to ElementTheme.colors.temporaryColorBgSpecial,
"bigCheckmarkBorderColor" to ElementTheme.colors.bigCheckmarkBorderColor,
) )
) )
} }

View file

@ -13,11 +13,17 @@ import android.net.Uri
import android.text.Spanned import android.text.Spanned
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.platform.LocalLayoutDirection
@ -28,6 +34,9 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.rememberTypeface import io.element.android.libraries.designsystem.text.rememberTypeface
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.messageFromMeBackground
import io.element.android.libraries.designsystem.theme.messageFromOtherBackground
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.di.SingleIn import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.MatrixClient
@ -48,7 +57,8 @@ import javax.inject.Inject
@Stable @Stable
@SingleIn(SessionScope::class) @SingleIn(SessionScope::class)
class MentionSpanTheme(val currentUserId: UserId) { class MentionSpanTheme(val currentUserId: UserId) {
@Inject constructor(matrixClient: MatrixClient) : this(matrixClient.sessionId) @Inject
constructor(matrixClient: MatrixClient) : this(matrixClient.sessionId)
internal var currentUserTextColor: Int = 0 internal var currentUserTextColor: Int = 0
internal var currentUserBackgroundColor: Int = Color.WHITE internal var currentUserBackgroundColor: Int = Color.WHITE
@ -162,3 +172,115 @@ internal fun MentionSpanThemePreview() {
}) })
} }
} }
@Composable
private fun MentionSpanThemeInTimelineContent(
bgColor: Int,
modifier: Modifier = Modifier,
) {
val mentionSpanTheme = remember { MentionSpanTheme(UserId("@me:matrix.org")) }
val provider = remember {
MentionSpanProvider(
mentionSpanTheme = mentionSpanTheme,
mentionSpanFormatter = object : MentionSpanFormatter {
override fun formatDisplayText(mentionType: MentionType): CharSequence {
return when (mentionType) {
is MentionType.User -> mentionType.userId.value
else -> throw AssertionError("Unexpected value $mentionType")
}
}
},
permalinkParser = object : PermalinkParser {
override fun parse(uriString: String): PermalinkData {
return when (uriString) {
"https://matrix.to/#/@me:matrix.org" -> PermalinkData.UserLink(UserId("@me:matrix.org"))
"https://matrix.to/#/@other:matrix.org" -> PermalinkData.UserLink(UserId("@other:matrix.org"))
else -> throw AssertionError("Unexpected value $uriString")
}
}
},
)
}
val textColor = ElementTheme.colors.textPrimary.toArgb()
fun mentionSpanMe() = provider.getMentionSpanFor("mention", "https://matrix.to/#/@me:matrix.org")
fun mentionSpanOther() = provider.getMentionSpanFor("mention", "https://matrix.to/#/@other:matrix.org")
mentionSpanTheme.updateStyles()
AndroidView(
modifier = modifier,
factory = { context ->
TextView(context).apply {
includeFontPadding = false
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
text = buildSpannedString {
append("Hello ")
append("@mention", mentionSpanMe(), 0)
append(" ")
append("@mention", mentionSpanOther(), 0)
}
setTextColor(textColor)
setBackgroundColor(bgColor)
}
}
)
}
@PreviewsDayNight
@Composable
internal fun MentionSpanThemeInTimelinePreview() = ElementPreview {
Column(
modifier = Modifier.padding(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
// Message from me
Text(
text = "Message from me",
style = ElementTheme.typography.fontBodySmMedium,
)
ElementTheme.colors.messageFromMeBackground.let { color ->
MentionSpanThemeInTimelineContent(
modifier = Modifier
.padding(start = 60.dp, end = 8.dp)
.background(
color = color,
shape = RoundedCornerShape(12.dp),
)
.padding(8.dp),
bgColor = color.toArgb()
)
}
// Message from other
ElementTheme.colors.messageFromOtherBackground.let { color ->
Text(
text = "Message from other",
style = ElementTheme.typography.fontBodySmMedium,
)
MentionSpanThemeInTimelineContent(
modifier = Modifier
.padding(start = 8.dp, end = 60.dp)
.padding(4.dp)
.background(
color = color,
shape = RoundedCornerShape(12.dp)
)
.padding(8.dp),
bgColor = color.toArgb()
)
}
// Composer
ElementTheme.colors.bgSubtleSecondary.let { color ->
Text(
text = "Composer",
style = ElementTheme.typography.fontBodySmMedium,
)
MentionSpanThemeInTimelineContent(
modifier = Modifier
.padding(start = 4.dp, end = 4.dp)
.background(color)
.padding(8.dp),
bgColor = color.toArgb()
)
}
}
}

View file

@ -73,6 +73,7 @@ class KonsistPreviewTest {
"MatrixBadgeAtomNegativePreview", "MatrixBadgeAtomNegativePreview",
"MatrixBadgeAtomNeutralPreview", "MatrixBadgeAtomNeutralPreview",
"MatrixBadgeAtomPositivePreview", "MatrixBadgeAtomPositivePreview",
"MentionSpanThemeInTimelinePreview",
"MessageComposerViewVoicePreview", "MessageComposerViewVoicePreview",
"MessagesReactionButtonAddPreview", "MessagesReactionButtonAddPreview",
"MessagesReactionButtonExtraPreview", "MessagesReactionButtonExtraPreview",

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6940c5b62364ff8a41b9600af5de950888d4050642a175d0bb13867e332fd360
size 8573

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5e71365efdbcbc0f0ad59e4be7d806a46ca72469f6b7f73a7c5d698405f637da
size 7217

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:447a51a65a22b90ddbc568cf031e0d83282cb0062a42aba274c592faf9148e70 oid sha256:2c99fdb4105bfec8eb22555171eeb1ae99ad8c43c7f2d402b2ab2bc509776484
size 56876 size 51537

View file

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:74f903d6fbe6a635dede1492ffc8a571b71a9645adfa59a648553c6d1716a1c0 oid sha256:7b0ee98accb2dbc445dbaf807c4ecb767b1d343c8b8388b37d6c13686cbaf09f
size 56228 size 51039

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7dbc2bbedaada6afcdcb121090084cf6ce59adb52b8c6ea2ee21a4177797cfe2
size 35562

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:5d6fe770605c0f9b2b9500692cd7725c1a0992e08eba2ae8700d05d9e171b05f
size 34490