mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-10 00:16:59 +00:00
fix(nests): avatar circular on narrow grid cells
The stage/audience LazyVerticalGrid uses Adaptive(80dp) cells while the avatar wants 75dp. Wrapping the avatar in an inner Box with `Modifier.padding(ringPadding=12dp)` reserved room for the speaking glow + outer ring, but it also reduced the avatar's max **width** to 56dp on a typical 82dp cell while leaving its height at the requested 75dp — Compose grid items are tight on width and free on height. Result: a 56×75 ellipse instead of a circle. Drop the inner padding and size the outer drawBehind Box explicitly to `avatarSize + ringPadding * 2`. AvatarAndBadges still sizes tight to the picture (so role/hand/mic/reaction badge corner alignment is unchanged), but no longer inherits a width-only constraint from the cell — the 75dp picture stays a circle.
This commit is contained in:
+50
-46
@@ -422,14 +422,18 @@ private fun MemberCell(
|
||||
label = "speaker-outer-ring-width",
|
||||
)
|
||||
// Reserve enough space around the avatar Box to fit the outer ring
|
||||
// and glow halo. Without this padding the rings clip against the
|
||||
// and glow halo. Without this margin the rings clip against the
|
||||
// surrounding Surface / LazyVerticalGrid bounds (most visibly at
|
||||
// the top edge for the first row, where the stage card's rounded
|
||||
// corner cuts into the glow). The glow extends up to MAX_GLOW_RADIUS
|
||||
// past the avatar; the outer ring extends OUTER_RING_GAP +
|
||||
// OUTER_RING_MAX_WIDTH past it.
|
||||
// OUTER_RING_MAX_WIDTH past it. Applied as an explicit outer-Box
|
||||
// size below rather than as inner padding so a width-constrained
|
||||
// grid cell doesn't squish the avatar horizontally into an oval
|
||||
// (cells are tight on width but free on height).
|
||||
val ringPadding =
|
||||
maxOf(MAX_GLOW_RADIUS.value, (OUTER_RING_GAP + OUTER_RING_MAX_WIDTH).value).dp
|
||||
val outerBoxSize = avatarSize + ringPadding * 2
|
||||
val avatarModifier =
|
||||
Modifier
|
||||
.border(animatedRingWidth, animatedRingColor, CircleShape)
|
||||
@@ -472,54 +476,54 @@ private fun MemberCell(
|
||||
modifier = modifier.fillMaxWidth().padding(vertical = 4.dp),
|
||||
) {
|
||||
// Outer Box paints the glow halo + detached outer ring on a
|
||||
// canvas that's bigger than the avatar by [ringPadding]. The
|
||||
// inner Box keeps its tight-to-avatar bounds so badge corner
|
||||
// alignment (TopStart, TopEnd, BottomCenter, BottomEnd) still
|
||||
// tracks the avatar circle, not the padded outer area.
|
||||
// canvas that's bigger than the avatar by [ringPadding]. Size
|
||||
// is set explicitly so the AvatarAndBadges child (which sizes
|
||||
// tight to the 75dp picture, keeping badge corner alignment
|
||||
// against the avatar circle rather than the padded area) is
|
||||
// centered without inheriting a width-only constraint from the
|
||||
// grid cell — that asymmetry was rendering the avatar as an
|
||||
// oval on cells narrower than [outerBoxSize].
|
||||
Box(
|
||||
modifier =
|
||||
Modifier.drawBehind {
|
||||
val avatarRadiusPx = avatarSize.toPx() / 2f
|
||||
val cx = size.width / 2f
|
||||
val cy = size.height / 2f
|
||||
if (animatedGlowAlpha > 0.001f) {
|
||||
val extra = MAX_GLOW_RADIUS.toPx() * clampedLevel
|
||||
drawCircle(
|
||||
color = NEST_SPEAKING_COLOR.copy(alpha = animatedGlowAlpha),
|
||||
radius = avatarRadiusPx + extra,
|
||||
center = Offset(cx, cy),
|
||||
)
|
||||
}
|
||||
if (animatedOuterRingAlpha > 0.001f && animatedOuterRingWidth > 0.dp) {
|
||||
val strokePx = animatedOuterRingWidth.toPx()
|
||||
val ringRadius = avatarRadiusPx + OUTER_RING_GAP.toPx() + strokePx / 2f
|
||||
drawCircle(
|
||||
color = NEST_SPEAKING_COLOR.copy(alpha = animatedOuterRingAlpha),
|
||||
radius = ringRadius,
|
||||
center = Offset(cx, cy),
|
||||
style = Stroke(width = strokePx),
|
||||
)
|
||||
}
|
||||
},
|
||||
Modifier
|
||||
.size(outerBoxSize)
|
||||
.drawBehind {
|
||||
val avatarRadiusPx = avatarSize.toPx() / 2f
|
||||
val cx = size.width / 2f
|
||||
val cy = size.height / 2f
|
||||
if (animatedGlowAlpha > 0.001f) {
|
||||
val extra = MAX_GLOW_RADIUS.toPx() * clampedLevel
|
||||
drawCircle(
|
||||
color = NEST_SPEAKING_COLOR.copy(alpha = animatedGlowAlpha),
|
||||
radius = avatarRadiusPx + extra,
|
||||
center = Offset(cx, cy),
|
||||
)
|
||||
}
|
||||
if (animatedOuterRingAlpha > 0.001f && animatedOuterRingWidth > 0.dp) {
|
||||
val strokePx = animatedOuterRingWidth.toPx()
|
||||
val ringRadius = avatarRadiusPx + OUTER_RING_GAP.toPx() + strokePx / 2f
|
||||
drawCircle(
|
||||
color = NEST_SPEAKING_COLOR.copy(alpha = animatedOuterRingAlpha),
|
||||
radius = ringRadius,
|
||||
center = Offset(cx, cy),
|
||||
style = Stroke(width = strokePx),
|
||||
)
|
||||
}
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.padding(ringPadding),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
AvatarAndBadges(
|
||||
member = member,
|
||||
avatarSize = avatarSize,
|
||||
accountViewModel = accountViewModel,
|
||||
avatarModifier = avatarModifier,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
isConnecting = isConnecting,
|
||||
showMicBadge = showMicBadge,
|
||||
isSpeaking = isSpeaking,
|
||||
reactions = reactions,
|
||||
)
|
||||
}
|
||||
AvatarAndBadges(
|
||||
member = member,
|
||||
avatarSize = avatarSize,
|
||||
accountViewModel = accountViewModel,
|
||||
avatarModifier = avatarModifier,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
isConnecting = isConnecting,
|
||||
showMicBadge = showMicBadge,
|
||||
isSpeaking = isSpeaking,
|
||||
reactions = reactions,
|
||||
)
|
||||
}
|
||||
UsernameDisplay(
|
||||
baseUser = user,
|
||||
|
||||
Reference in New Issue
Block a user