mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-02 12:07:28 +00:00
Merge pull request #7182 from element-hq/feature/bma/focussedButton
[A11y] Improve rendering on focused UI items
This commit is contained in:
@@ -16,7 +16,11 @@ import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
import androidx.compose.material3.ColorScheme
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.LocalRippleConfiguration
|
||||
import androidx.compose.material3.LocalRippleThemeConfiguration
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RippleConfiguration
|
||||
import androidx.compose.material3.RippleThemeConfiguration
|
||||
import androidx.compose.material3.Typography
|
||||
import androidx.compose.material3.dynamicDarkColorScheme
|
||||
import androidx.compose.material3.dynamicLightColorScheme
|
||||
@@ -28,6 +32,7 @@ import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.tokens.compoundTypography
|
||||
import io.element.android.compound.tokens.generated.SemanticColors
|
||||
import io.element.android.compound.tokens.generated.TypographyTokens
|
||||
@@ -159,6 +164,26 @@ fun ElementTheme(
|
||||
CompositionLocalProvider(
|
||||
LocalCompoundColors provides currentCompoundColor,
|
||||
LocalContentColor provides colorScheme.onSurface,
|
||||
// Configure the keyboard focus style: Draw a blue inset ring around the focused component.
|
||||
// Ref: https://www.figma.com/design/hlbsmSekQorGRN1t2R9JEy/Accessibility-checks?node-id=271-42066
|
||||
// By default, a semi-transparent black overlay is used
|
||||
LocalRippleThemeConfiguration provides RippleThemeConfiguration(
|
||||
RippleThemeConfiguration.Focus.InsetRing(
|
||||
outerStrokeInset = 0.dp,
|
||||
outerStrokeWidth = 2.dp,
|
||||
innerStrokeInset = 0.dp,
|
||||
innerStrokeWidth = 0.dp,
|
||||
)
|
||||
),
|
||||
// Configure the keyboard focus color.
|
||||
// By default, ColorScheme.secondary is used
|
||||
LocalRippleConfiguration provides
|
||||
RippleConfiguration(
|
||||
focus = RippleConfiguration.Focus.InsetRing(
|
||||
outerStrokeColor = ElementTheme.colors.borderFocused,
|
||||
innerStrokeColor = Color.Transparent,
|
||||
)
|
||||
),
|
||||
) {
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
|
||||
+65
-48
@@ -28,13 +28,15 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ButtonColors
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.LocalRippleThemeConfiguration
|
||||
import androidx.compose.material3.RippleThemeConfiguration
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.isSpecified
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
@@ -181,11 +183,8 @@ private fun ButtonInternal(
|
||||
ButtonSize.LargeLowPadding -> PaddingValues(horizontal = lowHorizontalPaddingValue, vertical = 13.dp)
|
||||
}
|
||||
|
||||
val shape = when (style) {
|
||||
ButtonStyle.Filled,
|
||||
ButtonStyle.Outlined -> RoundedCornerShape(percent = 50)
|
||||
ButtonStyle.Text -> RectangleShape
|
||||
}
|
||||
// Apply the same shape to all buttons, so that the focus ring is consistent across styles.
|
||||
val shape = RoundedCornerShape(percent = 50)
|
||||
|
||||
val border = when (style) {
|
||||
ButtonStyle.Filled -> null
|
||||
@@ -202,48 +201,66 @@ private fun ButtonInternal(
|
||||
ButtonStyle.Text -> null
|
||||
}
|
||||
|
||||
androidx.compose.material3.Button(
|
||||
onClick = {
|
||||
if (!showProgress) {
|
||||
onClick()
|
||||
}
|
||||
},
|
||||
modifier = modifier.heightIn(min = minHeight),
|
||||
enabled = enabled,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
elevation = null,
|
||||
border = border,
|
||||
contentPadding = contentPadding,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
// Reduce outerStrokeInset on Filled buttons so that it's displayed around the button
|
||||
val outerStrokeInset = when (style) {
|
||||
ButtonStyle.Filled -> (-4).dp
|
||||
ButtonStyle.Outlined,
|
||||
ButtonStyle.Text -> 0.dp
|
||||
}
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalRippleThemeConfiguration provides RippleThemeConfiguration(
|
||||
RippleThemeConfiguration.Focus.InsetRing(
|
||||
outerStrokeInset = outerStrokeInset,
|
||||
outerStrokeWidth = 2.dp,
|
||||
innerStrokeInset = 0.dp,
|
||||
innerStrokeWidth = 0.dp,
|
||||
)
|
||||
),
|
||||
) {
|
||||
when {
|
||||
showProgress -> {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.progressSemantics()
|
||||
.size(20.dp),
|
||||
color = LocalContentColor.current,
|
||||
strokeWidth = 2.dp,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
leadingIcon != null -> {
|
||||
Icon(
|
||||
painter = leadingIcon.getPainter(),
|
||||
contentDescription = null,
|
||||
tint = LocalContentColor.current,
|
||||
modifier = Modifier.size(20.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
androidx.compose.material3.Button(
|
||||
onClick = {
|
||||
if (!showProgress) {
|
||||
onClick()
|
||||
}
|
||||
},
|
||||
modifier = modifier.heightIn(min = minHeight),
|
||||
enabled = enabled,
|
||||
shape = shape,
|
||||
colors = colors,
|
||||
elevation = null,
|
||||
border = border,
|
||||
contentPadding = contentPadding,
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
) {
|
||||
when {
|
||||
showProgress -> {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.progressSemantics()
|
||||
.size(20.dp),
|
||||
color = LocalContentColor.current,
|
||||
strokeWidth = 2.dp,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
leadingIcon != null -> {
|
||||
Icon(
|
||||
painter = leadingIcon.getPainter(),
|
||||
contentDescription = null,
|
||||
tint = LocalContentColor.current,
|
||||
modifier = Modifier.size(20.dp),
|
||||
)
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = text,
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,7 +311,7 @@ internal enum class ButtonStyle {
|
||||
|
||||
@Composable
|
||||
fun getColors(destructive: Boolean): ButtonColors = when (this) {
|
||||
Filled -> ButtonDefaults.buttonColors(
|
||||
Filled -> ButtonDefaults.filledTonalButtonColors(
|
||||
containerColor = getPrimaryColor(destructive),
|
||||
contentColor = ElementTheme.materialColors.onPrimary,
|
||||
disabledContainerColor = if (destructive) {
|
||||
@@ -304,13 +321,13 @@ internal enum class ButtonStyle {
|
||||
},
|
||||
disabledContentColor = ElementTheme.colors.textOnSolidPrimary
|
||||
)
|
||||
Outlined -> ButtonDefaults.buttonColors(
|
||||
Outlined -> ButtonDefaults.outlinedButtonColors(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = getPrimaryColor(destructive),
|
||||
disabledContainerColor = Color.Transparent,
|
||||
disabledContentColor = getDisabledContentColor(destructive),
|
||||
)
|
||||
Text -> ButtonDefaults.buttonColors(
|
||||
Text -> ButtonDefaults.textButtonColors(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = if (destructive) {
|
||||
ElementTheme.colors.textCriticalPrimary
|
||||
|
||||
+1
-1
@@ -139,7 +139,7 @@ private fun SearchFieldContainer(
|
||||
border = BorderStroke(
|
||||
width = 1.dp,
|
||||
color = if (isFocused) {
|
||||
ElementTheme.colors.borderInteractiveHovered
|
||||
ElementTheme.colors.borderFocused
|
||||
} else {
|
||||
ElementTheme.colors.borderInteractiveSecondary
|
||||
}
|
||||
|
||||
+1
-1
@@ -293,8 +293,8 @@ private fun TextFieldContainer(
|
||||
width = if (isFocused) 2.dp else 1.dp,
|
||||
color = when {
|
||||
!enabled -> ElementTheme.colors.borderDisabled
|
||||
isFocused -> ElementTheme.colors.borderFocused
|
||||
isError -> ElementTheme.colors.borderCriticalPrimary
|
||||
isFocused -> ElementTheme.colors.borderInteractiveHovered
|
||||
else -> ElementTheme.colors.borderInteractiveSecondary
|
||||
}
|
||||
)
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Reference in New Issue
Block a user