Merge branch 'develop' into feature-oled-black

This commit is contained in:
Timur Gilfanov 2026-03-30 11:08:53 +04:00 committed by GitHub
commit d0dcbab750
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
1505 changed files with 14143 additions and 9545 deletions

View file

@ -8,14 +8,19 @@
package io.element.android.libraries.designsystem.atomic.atoms
import androidx.compose.foundation.BorderStroke
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.vector.ImageVector
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.components.Badge
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
/**
* https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=1960-491
*/
object MatrixBadgeAtom {
data class MatrixBadgeData(
val text: String,
@ -40,6 +45,12 @@ object MatrixBadgeAtom {
Type.Negative -> ElementTheme.colors.bgCriticalSubtle
Type.Info -> ElementTheme.colors.bgBadgeInfo
}
val borderStroke = when (data.type) {
Type.Positive -> null
Type.Neutral -> BorderStroke(1.dp, ElementTheme.colors.borderInteractiveSecondary)
Type.Negative -> null
Type.Info -> null
}
val textColor = when (data.type) {
Type.Positive -> ElementTheme.colors.textBadgeAccent
Type.Neutral -> ElementTheme.colors.textPrimary
@ -58,6 +69,7 @@ object MatrixBadgeAtom {
backgroundColor = backgroundColor,
iconColor = iconColor,
textColor = textColor,
borderStroke = borderStroke,
)
}
}

View file

@ -26,6 +26,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
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.colors.gradientCriticalColors
import io.element.android.libraries.designsystem.colors.gradientInfoColors
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarType
@ -38,13 +40,16 @@ import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.ui.strings.CommonStrings
/**
* Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=2392-6721
*/
@Composable
fun ComposerAlertMolecule(
avatar: AvatarData?,
content: AnnotatedString,
onSubmitClick: () -> Unit,
modifier: Modifier = Modifier,
level: ComposerAlertLevel = ComposerAlertLevel.Default,
level: ComposerAlertLevel = ComposerAlertLevel.Info,
showIcon: Boolean = false,
submitText: String = stringResource(CommonStrings.action_ok),
) {
@ -52,20 +57,12 @@ fun ComposerAlertMolecule(
modifier.fillMaxWidth()
) {
val lineColor = when (level) {
ComposerAlertLevel.Default -> ElementTheme.colors.borderInfoSubtle
ComposerAlertLevel.Info -> ElementTheme.colors.borderInfoSubtle
ComposerAlertLevel.Critical -> ElementTheme.colors.borderCriticalSubtle
}
val startColor = when (level) {
ComposerAlertLevel.Default -> ElementTheme.colors.bgInfoSubtle
ComposerAlertLevel.Info -> ElementTheme.colors.bgInfoSubtle
ComposerAlertLevel.Critical -> ElementTheme.colors.bgCriticalSubtle
}
val textColor = when (level) {
ComposerAlertLevel.Default -> ElementTheme.colors.textPrimary
ComposerAlertLevel.Info -> ElementTheme.colors.textInfoPrimary
ComposerAlertLevel.Info -> ElementTheme.colors.textPrimary
ComposerAlertLevel.Critical -> ElementTheme.colors.textCriticalPrimary
}
@ -75,12 +72,13 @@ fun ComposerAlertMolecule(
.height(1.dp)
.background(lineColor)
)
val brush = Brush.verticalGradient(
listOf(startColor, ElementTheme.colors.bgCanvasDefault),
)
val gradientColors = when (level) {
ComposerAlertLevel.Info -> gradientInfoColors()
ComposerAlertLevel.Critical -> gradientCriticalColors()
}
Box(
modifier = Modifier
.background(brush)
.background(Brush.verticalGradient(gradientColors))
.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 8.dp)
) {
Column(
@ -96,12 +94,10 @@ fun ComposerAlertMolecule(
)
} else if (showIcon) {
val icon = when (level) {
ComposerAlertLevel.Default -> CompoundIcons.Info()
ComposerAlertLevel.Info -> CompoundIcons.Info()
ComposerAlertLevel.Critical -> CompoundIcons.Error()
}
val iconTint = when (level) {
ComposerAlertLevel.Default -> ElementTheme.colors.iconPrimary
ComposerAlertLevel.Info -> ElementTheme.colors.iconInfoPrimary
ComposerAlertLevel.Critical -> ElementTheme.colors.iconCriticalPrimary
}
@ -131,7 +127,6 @@ fun ComposerAlertMolecule(
}
enum class ComposerAlertLevel {
Default,
Info,
Critical
}

View file

@ -21,7 +21,6 @@ internal data class ComposerAlertMoleculeParams(
internal class ComposerAlertMoleculeParamsProvider : PreviewParameterProvider<ComposerAlertMoleculeParams> {
private val allLevels = sequenceOf(
ComposerAlertLevel.Default,
ComposerAlertLevel.Info,
ComposerAlertLevel.Critical
)

View file

@ -38,8 +38,11 @@ fun gradientSubtleColors(): List<Color> = listOf(
fun gradientInfoColors(): List<Color> = listOf(
ElementTheme.colors.gradientInfoStop1,
ElementTheme.colors.gradientInfoStop2,
ElementTheme.colors.gradientInfoStop3,
ElementTheme.colors.gradientInfoStop4,
ElementTheme.colors.gradientInfoStop5,
ElementTheme.colors.gradientInfoStop6,
)
@Composable
@ReadOnlyComposable
fun gradientCriticalColors(): List<Color> = listOf(
ElementTheme.colors.gradientCriticalStop1,
ElementTheme.colors.gradientCriticalStop2,
)

View file

@ -0,0 +1,419 @@
/*
* Copyright (c) 2026 Element Creations 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 android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.Path
import android.graphics.Rect
import android.graphics.RectF
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.produceState
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.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import androidx.core.graphics.createBitmap
import androidx.core.graphics.withSave
import coil3.Image
import coil3.ImageLoader
import coil3.SingletonImageLoader
import coil3.asImage
import coil3.memory.MemoryCache
import coil3.request.ImageRequest
import coil3.request.allowHardware
import coil3.toBitmap
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.colors.AvatarColorsProvider
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
private val PIN_WIDTH = 42.dp
private val PIN_HEIGHT = PIN_WIDTH * 1.2f
private val AVATAR_SIZE = PIN_WIDTH - 10.dp
private val CONTENT_OFFSET = 5.dp
private val DOT_RADIUS = 6.dp
private val STROKE_WIDTH = 1.dp
/**
* Variants of location pin markers.
*/
@Immutable
sealed interface PinVariant {
data class UserLocation(
val avatarData: AvatarData,
val isLive: Boolean,
) : PinVariant
data object PinnedLocation : PinVariant
data object StaleLocation : PinVariant
}
/**
* A location pin composable that supports multiple variants.
*
* Based on Figma design: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=4665-2890&m=dev
*/
@Composable
fun LocationPin(
variant: PinVariant,
modifier: Modifier = Modifier,
) {
val image = rememberLocationPinBitmap(variant)
Canvas(modifier = modifier.size(PIN_WIDTH, PIN_HEIGHT)) {
if (image != null) {
drawImage(image)
}
}
}
/**
* Renders a location pin to an [ImageBitmap] using Canvas operations.
* @param variant The pin variant to render
* @return The rendered [ImageBitmap], or null if still loading
*/
@Composable
fun rememberLocationPinBitmap(variant: PinVariant): ImageBitmap? {
val context = LocalContext.current
val density = LocalDensity.current
val imageLoader = SingletonImageLoader.get(context)
val colors = pinColors(variant)
val cacheKey = rememberCacheKey(variant)
return produceState<ImageBitmap?>(initialValue = null, cacheKey) {
val memoryCacheKey = MemoryCache.Key(cacheKey)
val cached = imageLoader.memoryCache?.get(memoryCacheKey)
if (cached != null) {
value = cached.image.toBitmap().asImageBitmap()
} else {
val dimensions = PinDimensions(density)
val bitmap = LocationPinRenderer.renderPin(variant, colors, dimensions, context, imageLoader)
imageLoader.memoryCache?.set(memoryCacheKey, MemoryCache.Value(bitmap.asImage()))
value = bitmap.asImageBitmap()
}
}.value
}
@Composable
private fun pinColors(variant: PinVariant): PinColors {
return when (variant) {
is PinVariant.UserLocation -> {
val avatarColors = AvatarColorsProvider.provide(variant.avatarData.id)
if (variant.isLive) {
PinColors(
fill = ElementTheme.colors.iconAccentPrimary,
stroke = Color.Transparent,
dot = Color.Transparent,
avatarStroke = ElementTheme.colors.bgCanvasDefault,
avatarBackground = avatarColors.background,
avatarForeground = avatarColors.foreground,
)
} else {
PinColors(
fill = ElementTheme.colors.bgCanvasDefault,
stroke = ElementTheme.colors.iconQuaternaryAlpha,
dot = Color.Transparent,
avatarStroke = ElementTheme.colors.iconQuaternaryAlpha,
avatarBackground = avatarColors.background,
avatarForeground = avatarColors.foreground,
)
}
}
PinVariant.PinnedLocation -> PinColors(
fill = ElementTheme.colors.bgCanvasDefault,
stroke = ElementTheme.colors.iconSecondaryAlpha,
avatarStroke = Color.Transparent,
avatarBackground = Color.Transparent,
avatarForeground = Color.Transparent,
dot = ElementTheme.colors.iconPrimary,
)
PinVariant.StaleLocation -> PinColors(
fill = ElementTheme.colors.bgSubtleSecondary,
stroke = ElementTheme.colors.iconDisabled,
avatarStroke = Color.Transparent,
avatarBackground = Color.Transparent,
avatarForeground = Color.Transparent,
dot = ElementTheme.colors.iconDisabled,
)
}
}
/**
* Color configuration for rendering a location pin.
*/
private data class PinColors(
val fill: Color,
val stroke: Color,
val dot: Color,
val avatarStroke: Color,
val avatarBackground: Color,
val avatarForeground: Color,
)
/**
* Pre-calculated pixel dimensions for rendering a location pin.
*/
private class PinDimensions(density: Density) {
val pinWidth = with(density) { PIN_WIDTH.toPx() }
val pinHeight = with(density) { PIN_HEIGHT.toPx() }
val avatarSize: Float = with(density) { AVATAR_SIZE.toPx() }
val avatarOffset: Float = with(density) { CONTENT_OFFSET.toPx() }
val dotRadius: Float = with(density) { DOT_RADIUS.toPx() }
val strokeWidth: Float = with(density) { STROKE_WIDTH.toPx() }
}
/**
* Renders location pins to bitmaps using Canvas operations.
* Uses Coil for avatar loading.
* Paint objects are shared across all renders.
*/
private object LocationPinRenderer {
// Shared Paint objects to avoid allocations
private val fillPaint = Paint().apply {
style = Paint.Style.FILL
isAntiAlias = true
}
private val strokePaint = Paint().apply {
style = Paint.Style.STROKE
isAntiAlias = true
}
private val textPaint = Paint().apply {
textAlign = Paint.Align.CENTER
isAntiAlias = true
isFakeBoldText = true
}
/**
* Renders a pin variant to bitmap. Suspending for async avatar loading.
*/
suspend fun renderPin(
variant: PinVariant,
colors: PinColors,
dimensions: PinDimensions,
context: Context,
imageLoader: ImageLoader,
): Bitmap {
val bitmap = createBitmap(dimensions.pinWidth.toInt(), dimensions.pinHeight.toInt())
val canvas = Canvas(bitmap)
canvas.drawPinShape(colors.fill, colors.stroke, dimensions)
when (variant) {
is PinVariant.UserLocation -> {
val avatarImage = loadAvatarImage(variant.avatarData, context, imageLoader)
canvas.drawAvatar(
avatarImage = avatarImage,
avatarData = variant.avatarData,
borderColor = colors.avatarStroke,
backgroundColor = colors.avatarBackground,
foregroundColor = colors.avatarForeground,
dimensions = dimensions,
)
}
PinVariant.PinnedLocation,
PinVariant.StaleLocation -> canvas.drawDot(colors.dot, dimensions)
}
return bitmap
}
private fun Canvas.drawPinShape(fillColor: Color, strokeColor: Color, dimensions: PinDimensions) {
val path = createPinPath(dimensions)
fillPaint.color = fillColor.toArgb()
drawPath(path, fillPaint)
strokePaint.color = strokeColor.toArgb()
strokePaint.strokeWidth = dimensions.strokeWidth
drawPath(path, strokePaint)
}
/**
* Updates the teardrop-shaped pin path to match dimensions.
* Based on SVG path with dimensions 40x48 (ratio 1:1.2).
*/
private fun createPinPath(dimensions: PinDimensions): Path {
val svgWidth = 40f
val svgHeight = 48f
val inset = dimensions.strokeWidth / 2
val scaleX = (dimensions.pinWidth - dimensions.strokeWidth) / svgWidth
val scaleY = (dimensions.pinHeight - dimensions.strokeWidth) / svgHeight
val path = Path().apply {
moveTo(20f, 48f)
cubicTo(19.4167f, 48f, 18.8333f, 47.8965f, 18.25f, 47.6895f)
cubicTo(17.6667f, 47.4825f, 17.1458f, 47.1721f, 16.6875f, 46.7581f)
cubicTo(13.9792f, 44.2743f, 11.5833f, 41.8525f, 9.5f, 39.4929f)
cubicTo(7.41667f, 37.1332f, 5.67708f, 34.8461f, 4.28125f, 32.6313f)
cubicTo(2.88542f, 30.4166f, 1.82292f, 28.2846f, 1.09375f, 26.2354f)
cubicTo(0.364583f, 24.1863f, 0f, 22.2303f, 0f, 20.3674f)
cubicTo(0f, 14.1578f, 2.01042f, 9.21087f, 6.03125f, 5.52652f)
cubicTo(10.0521f, 1.84217f, 14.7083f, 0f, 20f, 0f)
cubicTo(25.2917f, 0f, 29.9479f, 1.84217f, 33.9688f, 5.52652f)
cubicTo(37.9896f, 9.21087f, 40f, 14.1578f, 40f, 20.3674f)
cubicTo(40f, 22.2303f, 39.6354f, 24.1863f, 38.9062f, 26.2354f)
cubicTo(38.1771f, 28.2846f, 37.1146f, 30.4166f, 35.7188f, 32.6313f)
cubicTo(34.3229f, 34.8461f, 32.5833f, 37.1332f, 30.5f, 39.4929f)
cubicTo(28.4167f, 41.8525f, 26.0208f, 44.2743f, 23.3125f, 46.7581f)
cubicTo(22.8542f, 47.1721f, 22.3333f, 47.4825f, 21.75f, 47.6895f)
cubicTo(21.1667f, 47.8965f, 20.5833f, 48f, 20f, 48f)
close()
}
val matrix = Matrix().apply {
setScale(scaleX, scaleY)
postTranslate(inset, inset)
}
path.transform(matrix)
return path
}
private suspend fun loadAvatarImage(
avatarData: AvatarData,
context: Context,
imageLoader: ImageLoader,
): Image? {
val request = ImageRequest.Builder(context)
.data(avatarData)
// Disable hardware rendering for Canvas
.allowHardware(false)
.build()
return imageLoader.execute(request).image
}
private fun Canvas.drawAvatar(
avatarImage: Image?,
avatarData: AvatarData,
borderColor: Color,
backgroundColor: Color,
foregroundColor: Color,
dimensions: PinDimensions,
) {
val centerX = dimensions.pinWidth / 2
val avatarY = dimensions.avatarOffset
val avatarRadius = dimensions.avatarSize / 2
withSave {
if (avatarImage != null) {
val bitmap = avatarImage.toBitmap()
// Calculate centered square crop (ContentScale.Crop behavior)
val srcSize = minOf(bitmap.width, bitmap.height)
val srcX = (bitmap.width - srcSize) / 2
val srcY = (bitmap.height - srcSize) / 2
val srcRect = Rect(srcX, srcY, srcX + srcSize, srcY + srcSize)
val destRect = RectF(
centerX - avatarRadius,
avatarY,
centerX + avatarRadius,
avatarY + dimensions.avatarSize
)
val clipPath = Path().apply {
addCircle(centerX, avatarY + avatarRadius, avatarRadius, Path.Direction.CW)
}
clipPath(clipPath)
drawBitmap(bitmap, srcRect, destRect, null)
} else {
drawInitialLetterAvatar(
initialLetter = avatarData.initialLetter,
centerX = centerX,
centerY = avatarY + avatarRadius,
radius = avatarRadius,
foreground = foregroundColor.toArgb(),
background = backgroundColor.toArgb()
)
}
}
strokePaint.color = borderColor.toArgb()
strokePaint.strokeWidth = dimensions.strokeWidth
drawCircle(centerX, avatarY + avatarRadius, avatarRadius, strokePaint)
}
private fun Canvas.drawInitialLetterAvatar(
initialLetter: String,
centerX: Float,
centerY: Float,
radius: Float,
foreground: Int,
background: Int,
) {
fillPaint.color = background
drawCircle(centerX, centerY, radius, fillPaint)
textPaint.color = foreground
textPaint.textSize = radius * 1.2f
val textBounds = Rect()
textPaint.getTextBounds(initialLetter, 0, 1, textBounds)
val textY = centerY + textBounds.height() / 2f
drawText(initialLetter, centerX, textY, textPaint)
}
private fun Canvas.drawDot(dotColor: Color, dimensions: PinDimensions) {
if (dotColor == Color.Transparent) return
val centerX = dimensions.pinWidth / 2
val centerY = dimensions.avatarOffset + dimensions.avatarSize / 2
fillPaint.color = dotColor.toArgb()
drawCircle(centerX, centerY, dimensions.dotRadius, fillPaint)
}
}
@PreviewsDayNight
@Composable
internal fun LocationPinPreview() = ElementPreview {
val sampleAvatarData = AvatarData(
id = "@alice:matrix.org",
name = "Alice",
url = null,
size = AvatarSize.SelectedUser
)
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
LocationPin(
variant = PinVariant.UserLocation(avatarData = sampleAvatarData, isLive = false),
)
LocationPin(
variant = PinVariant.UserLocation(avatarData = sampleAvatarData, isLive = true),
)
}
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
LocationPin(
variant = PinVariant.PinnedLocation,
)
LocationPin(
variant = PinVariant.StaleLocation,
)
}
}
}
@Composable
private fun rememberCacheKey(variant: PinVariant): String {
val isLightTheme = ElementTheme.isLightTheme
val density = LocalDensity.current.density
return remember(isLightTheme, density, variant) {
val pinVariant = when (variant) {
PinVariant.PinnedLocation -> "pin_pinned"
PinVariant.StaleLocation -> "pin_stale"
is PinVariant.UserLocation -> "pin_user_${variant.avatarData.id}_${variant.isLive}"
}
"${pinVariant}_{$isLightTheme}_{$density}"
}
}

View file

@ -1,48 +0,0 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 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.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.libraries.designsystem.R
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Icon
@Composable
fun PinIcon(
modifier: Modifier = Modifier
) {
Box(
modifier = modifier
.background(ElementTheme.colors.bgSubtlePrimary)
) {
Icon(
modifier = Modifier
.align(Alignment.Center)
.width(22.dp),
resourceId = R.drawable.pin,
contentDescription = null,
tint = Color.Unspecified,
)
}
}
@PreviewsDayNight
@Composable
internal fun PinIconPreview() = ElementPreview {
PinIcon()
}

View file

@ -46,7 +46,8 @@ enum class AvatarSize(val dp: Dp) {
RoomInviteItem(52.dp),
InviteSender(16.dp),
EditRoomDetails(68.dp),
EditRoomDetails(64.dp),
EditSpaceDetails(96.dp),
RoomListManageUser(96.dp),
NotificationsOptIn(32.dp),
@ -75,6 +76,6 @@ enum class AvatarSize(val dp: Dp) {
SpaceMember(24.dp),
LeaveSpaceRoom(32.dp),
SelectParentSpace(32.dp),
AccountItem(32.dp),
LocationPin(32.dp)
}

View file

@ -42,6 +42,7 @@ fun ListDialog(
enabled: Boolean = true,
applyPaddingToContents: Boolean = true,
destructiveSubmit: Boolean = false,
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(16.dp),
listItems: LazyListScope.() -> Unit,
) {
val decoratedSubtitle: @Composable (() -> Unit)? = subtitle?.let {
@ -67,6 +68,7 @@ fun ListDialog(
listItems = listItems,
applyPaddingToContents = applyPaddingToContents,
destructiveSubmit = destructiveSubmit,
verticalArrangement = verticalArrangement,
)
}
}
@ -82,6 +84,7 @@ private fun ListDialogContent(
enabled: Boolean,
applyPaddingToContents: Boolean,
destructiveSubmit: Boolean,
verticalArrangement: Arrangement.Vertical,
subtitle: @Composable (() -> Unit)? = null,
) {
SimpleAlertDialogContent(
@ -99,7 +102,7 @@ private fun ListDialogContent(
val horizontalPadding = if (applyPaddingToContents) 0.dp else 8.dp
LazyColumn(
modifier = Modifier.padding(horizontal = horizontalPadding),
verticalArrangement = Arrangement.spacedBy(16.dp),
verticalArrangement = verticalArrangement,
) { listItems() }
}
}
@ -126,6 +129,7 @@ internal fun ListDialogContentPreview() {
enabled = true,
destructiveSubmit = false,
applyPaddingToContents = true,
verticalArrangement = Arrangement.spacedBy(16.dp),
)
}
}

View file

@ -14,7 +14,6 @@ import io.element.android.libraries.designsystem.R
// All the icons should be defined in Compound.
internal val iconsOther = listOf(
R.drawable.ic_notification,
R.drawable.ic_stop,
R.drawable.pin,
R.drawable.ic_winner,
)

View file

@ -20,9 +20,9 @@ import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.graphics.AndroidPaint
import androidx.compose.ui.graphics.ClipOp
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
@ -55,10 +55,10 @@ fun Modifier.blurredShapeShadow(
addRoundRect(RoundRect(Rect(Offset.Zero, size), CornerRadius(cornerRadius.toPx())))
}
val frameworkPaint = android.graphics.Paint()
// Draw the blurred shadow, then cut out the shape from it
clipPath(path, ClipOp.Difference) {
val paint = Paint()
val frameworkPaint = paint.asFrameworkPaint()
val paint = AndroidPaint(frameworkPaint)
if (blurRadius != 0.dp) {
frameworkPaint.maskFilter = BlurMaskFilter(blurRadius.toPx(), BlurMaskFilter.Blur.NORMAL)
}

View file

@ -54,7 +54,7 @@ fun ModalBottomSheet(
tonalElevation: Dp = if (ElementTheme.isLightTheme) 0.dp else BottomSheetDefaults.Elevation,
scrimColor: Color = BottomSheetDefaults.ScrimColor,
dragHandle: @Composable (() -> Unit)? = { BottomSheetDefaults.DragHandle() },
contentWindowInsets: @Composable () -> WindowInsets = { BottomSheetDefaults.windowInsets },
contentWindowInsets: @Composable () -> WindowInsets = { BottomSheetDefaults.modalWindowInsets },
content: @Composable ColumnScope.() -> Unit,
) {
val safeSheetState = if (LocalInspectionMode.current) sheetStateForPreview() else sheetState

View file

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M6,16V8C6,7.45 6.196,6.979 6.588,6.588C6.979,6.196 7.45,6 8,6H16C16.55,6 17.021,6.196 17.413,6.588C17.804,6.979 18,7.45 18,8V16C18,16.55 17.804,17.021 17.413,17.413C17.021,17.804 16.55,18 16,18H8C7.45,18 6.979,17.804 6.588,17.413C6.196,17.021 6,16.55 6,16Z"
android:fillColor="#ffffff"/>
</vector>