feat: add dynamic blur effect to avatar based on proximity to notch in ProfileMetaballOverlay

This commit is contained in:
k1ngsterr1
2026-02-01 03:54:01 +05:00
parent a61887cc5b
commit 67920cf695

View File

@@ -260,6 +260,16 @@ fun ProfileMetaballOverlay(
// Should we draw the connector? (when avatar gets close enough)
val showConnector = collapseProgress > 0.3f && avatarState.showBlob && distance < maxDist * 2f
// Calculate blur intensity for avatar based on distance to notch (like Telegram)
// When avatar is far - no blur, when close - more blur
val avatarBlurRadius = if (showConnector) {
// More blur as avatar gets closer to notch
val nearProgress = (1f - (distance / maxDist).coerceIn(0f, 1f))
(nearProgress * ProfileMetaballConstants.BLUR_RADIUS * 0.5f).coerceIn(0f, 10f)
} else {
0f
}
Box(modifier = modifier.fillMaxSize()) {
// LAYER 1: Metaball shapes with blur effect (BLACK shapes only)
Canvas(
@@ -267,18 +277,16 @@ fun ProfileMetaballOverlay(
.fillMaxSize()
.graphicsLayer {
metaShader.setFloatUniform("cutoff", ProfileMetaballConstants.CUTOFF)
renderEffect = RenderEffect
.createBlurEffect(
ProfileMetaballConstants.BLUR_RADIUS,
ProfileMetaballConstants.BLUR_RADIUS,
Shader.TileMode.DECAL
)
.let { blurEffect ->
RenderEffect.createChainEffect(
RenderEffect.createRuntimeShaderEffect(metaShader, "composable"),
blurEffect
)
}
// IMPORTANT: First blur, THEN threshold shader
// createChainEffect(outer, inner) - inner is applied first
val blurEffect = RenderEffect.createBlurEffect(
ProfileMetaballConstants.BLUR_RADIUS,
ProfileMetaballConstants.BLUR_RADIUS,
Shader.TileMode.DECAL
)
val thresholdEffect = RenderEffect.createRuntimeShaderEffect(metaShader, "composable")
// Chain: blur first (inner), then threshold (outer)
renderEffect = RenderEffect.createChainEffect(thresholdEffect, blurEffect)
.asComposeRenderEffect()
}
) {
@@ -343,7 +351,7 @@ fun ProfileMetaballOverlay(
}
}
// LAYER 2: Actual avatar content (NO BLUR!) - rendered on top
// LAYER 2: Actual avatar content - with blur when close to notch
if (avatarState.showBlob) {
val avatarSizeDp = with(density) { (avatarState.radius * 2f).toDp() }
val avatarOffsetX = with(density) { (avatarState.centerX - avatarState.radius).toDp() }
@@ -357,6 +365,14 @@ fun ProfileMetaballOverlay(
.clip(RoundedCornerShape(avatarSizeDp / 2))
.graphicsLayer {
alpha = avatarState.opacity
// Apply blur to avatar when close to notch (like Telegram)
if (avatarBlurRadius > 0.5f) {
renderEffect = RenderEffect.createBlurEffect(
avatarBlurRadius,
avatarBlurRadius,
Shader.TileMode.DECAL
).asComposeRenderEffect()
}
},
contentAlignment = Alignment.Center,
content = avatarContent