Skip to content

Commit 9485ac2

Browse files
author
Ken Ackerson
committed
Update SelfieScreen.kt
1 parent 3ee8a4f commit 9485ac2

1 file changed

Lines changed: 108 additions & 56 deletions

File tree

identity/src/main/java/com/stripe/android/identity/ui/SelfieScreen.kt

Lines changed: 108 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import android.graphics.Paint
55
import android.graphics.RadialGradient
66
import android.graphics.Shader
77
import androidx.annotation.StringRes
8+
import androidx.compose.animation.core.Animatable
89
import androidx.compose.animation.core.FastOutSlowInEasing
910
import androidx.compose.animation.core.LinearEasing
1011
import androidx.compose.animation.core.animateFloatAsState
@@ -113,15 +114,15 @@ private const val CAPTURE_GUIDE_VERTICAL_DIAMETER_RATIO = 0.56f
113114
// FaceDetectorTransitioner validates centering against the normalized image center.
114115
private const val CAPTURE_GUIDE_CENTER_Y_RATIO = 0.5f
115116
private const val CAPTURE_GUIDE_SHADOW_ANIMATION_TIME = 180
116-
private const val CAPTURE_GUIDE_SHADOW_FEATHER_DP = 44
117-
private const val CAPTURE_GUIDE_SHADOW_CLEAR_STOP_MAX = 0.96f
118-
private const val CAPTURE_GUIDE_SHADOW_FIRST_VISIBLE_STOP_OFFSET = 0.012f
119-
private const val CAPTURE_GUIDE_SHADOW_FIRST_VISIBLE_STOP_MAX = 0.98f
120-
private const val CAPTURE_GUIDE_SHADOW_FEATHER_STOP_OFFSET = 0.02f
121-
private const val CAPTURE_GUIDE_SHADOW_FEATHER_STOP_MAX = 0.99f
122-
private const val CAPTURE_GUIDE_SHADOW_INNER_ALPHA = 0.20f
123-
private const val CAPTURE_GUIDE_SHADOW_MID_ALPHA = 0.24f
124-
private const val CAPTURE_GUIDE_SHADOW_OUTER_ALPHA = 0.28f
117+
private const val CAPTURE_GUIDE_SHADOW_FEATHER_DP = 34
118+
private const val CAPTURE_GUIDE_SHADOW_FEATHER_LOCATION_MIN = 0.06f
119+
private const val CAPTURE_GUIDE_SHADOW_FEATHER_LOCATION_MAX = 0.96f
120+
private const val CAPTURE_GUIDE_SHADOW_INNER_LOCATION_FACTOR = 0.25f
121+
private const val CAPTURE_GUIDE_SHADOW_MID_LOCATION_FACTOR = 0.6f
122+
private const val CAPTURE_GUIDE_SHADOW_INNER_ALPHA = 0.14f
123+
private const val CAPTURE_GUIDE_SHADOW_MID_ALPHA = 0.28f
124+
private const val CAPTURE_GUIDE_SHADOW_RING_ALPHA = 0.36f
125+
private const val CAPTURE_GUIDE_SHADOW_OUTER_ALPHA = 0.42f
125126
private const val CAPTURE_GUIDE_TICK_ALPHA = 0.8f
126127
private const val CAPTURE_GUIDE_TICK_SHADOW_ALPHA = 0.3f
127128
private const val CAPTURED_SELFIE_OVERLAY_ALPHA = 0.16f
@@ -489,14 +490,10 @@ private fun DrawScope.drawCenteredGuideShadow(
489490
}
490491

491492
val featherRadius = min(verticalRadius + CAPTURE_GUIDE_SHADOW_FEATHER_DP.dp.toPx(), outerRadius)
492-
val clearStop = (clearRadius / outerRadius).coerceIn(0f, CAPTURE_GUIDE_SHADOW_CLEAR_STOP_MAX)
493-
val firstVisibleStop = min(
494-
clearStop + CAPTURE_GUIDE_SHADOW_FIRST_VISIBLE_STOP_OFFSET,
495-
CAPTURE_GUIDE_SHADOW_FIRST_VISIBLE_STOP_MAX
496-
)
497-
val featherStop = min(
498-
max(featherRadius / outerRadius, firstVisibleStop + CAPTURE_GUIDE_SHADOW_FEATHER_STOP_OFFSET),
499-
CAPTURE_GUIDE_SHADOW_FEATHER_STOP_MAX
493+
val gradientStops = centeredGuideShadowGradientStops(
494+
clearRadius = clearRadius,
495+
featherRadius = featherRadius,
496+
outerRadius = outerRadius
500497
)
501498
val shadowOpacity = opacity.coerceIn(0f, 1f)
502499

@@ -506,39 +503,90 @@ private fun DrawScope.drawCenteredGuideShadow(
506503
nativeCanvas.translate(center.x, center.y)
507504
nativeCanvas.scale(scaleX, 1f)
508505

509-
val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
510-
style = Paint.Style.FILL
511-
shader = RadialGradient(
512-
0f,
513-
0f,
514-
outerRadius,
515-
intArrayOf(
516-
Color.Transparent.toArgb(),
517-
Color.Transparent.toArgb(),
518-
Color.Black.copy(alpha = CAPTURE_GUIDE_SHADOW_INNER_ALPHA * shadowOpacity).toArgb(),
519-
Color.Black.copy(alpha = CAPTURE_GUIDE_SHADOW_MID_ALPHA * shadowOpacity).toArgb(),
520-
Color.Black.copy(alpha = CAPTURE_GUIDE_SHADOW_OUTER_ALPHA * shadowOpacity).toArgb()
521-
),
522-
floatArrayOf(
523-
0f,
524-
clearStop,
525-
firstVisibleStop,
526-
featherStop,
527-
1f
528-
),
529-
Shader.TileMode.CLAMP
530-
)
531-
}
532-
val shadowPath = AndroidPath().apply {
533-
fillType = AndroidPath.FillType.EVEN_ODD
534-
addCircle(0f, 0f, outerRadius, AndroidPath.Direction.CW)
535-
addCircle(0f, 0f, clearRadius, AndroidPath.Direction.CW)
536-
}
537-
nativeCanvas.drawPath(shadowPath, paint)
506+
nativeCanvas.drawPath(
507+
centeredGuideShadowPath(outerRadius, clearRadius),
508+
centeredGuideShadowPaint(outerRadius, gradientStops, shadowOpacity)
509+
)
538510
nativeCanvas.restore()
539511
}
540512
}
541513

514+
private data class CenteredGuideShadowGradientStops(
515+
val clear: Float,
516+
val inner: Float,
517+
val mid: Float,
518+
val ring: Float
519+
)
520+
521+
private fun centeredGuideShadowGradientStops(
522+
clearRadius: Float,
523+
featherRadius: Float,
524+
outerRadius: Float
525+
): CenteredGuideShadowGradientStops {
526+
val shadowSpan = outerRadius - clearRadius
527+
val featherLocation = min(
528+
max(
529+
(featherRadius - clearRadius) / shadowSpan,
530+
CAPTURE_GUIDE_SHADOW_FEATHER_LOCATION_MIN
531+
),
532+
CAPTURE_GUIDE_SHADOW_FEATHER_LOCATION_MAX
533+
)
534+
535+
fun absoluteStop(relativeLocation: Float): Float {
536+
return (clearRadius + (shadowSpan * relativeLocation)) / outerRadius
537+
}
538+
539+
return CenteredGuideShadowGradientStops(
540+
clear = clearRadius / outerRadius,
541+
inner = absoluteStop(featherLocation * CAPTURE_GUIDE_SHADOW_INNER_LOCATION_FACTOR),
542+
mid = absoluteStop(featherLocation * CAPTURE_GUIDE_SHADOW_MID_LOCATION_FACTOR),
543+
ring = absoluteStop(featherLocation)
544+
)
545+
}
546+
547+
private fun centeredGuideShadowPaint(
548+
outerRadius: Float,
549+
gradientStops: CenteredGuideShadowGradientStops,
550+
shadowOpacity: Float
551+
): Paint {
552+
return Paint(Paint.ANTI_ALIAS_FLAG).apply {
553+
style = Paint.Style.FILL
554+
shader = RadialGradient(
555+
0f,
556+
0f,
557+
outerRadius,
558+
intArrayOf(
559+
Color.Transparent.toArgb(),
560+
Color.Transparent.toArgb(),
561+
Color.Black.copy(alpha = CAPTURE_GUIDE_SHADOW_INNER_ALPHA * shadowOpacity).toArgb(),
562+
Color.Black.copy(alpha = CAPTURE_GUIDE_SHADOW_MID_ALPHA * shadowOpacity).toArgb(),
563+
Color.Black.copy(alpha = CAPTURE_GUIDE_SHADOW_RING_ALPHA * shadowOpacity).toArgb(),
564+
Color.Black.copy(alpha = CAPTURE_GUIDE_SHADOW_OUTER_ALPHA * shadowOpacity).toArgb()
565+
),
566+
floatArrayOf(
567+
0f,
568+
gradientStops.clear,
569+
gradientStops.inner,
570+
gradientStops.mid,
571+
gradientStops.ring,
572+
1f
573+
),
574+
Shader.TileMode.CLAMP
575+
)
576+
}
577+
}
578+
579+
private fun centeredGuideShadowPath(
580+
outerRadius: Float,
581+
clearRadius: Float
582+
): AndroidPath {
583+
return AndroidPath().apply {
584+
fillType = AndroidPath.FillType.EVEN_ODD
585+
addCircle(0f, 0f, outerRadius, AndroidPath.Direction.CW)
586+
addCircle(0f, 0f, clearRadius, AndroidPath.Direction.CW)
587+
}
588+
}
589+
542590
@Composable
543591
private fun SelfieStatusBadge(
544592
status: SelfieStatus,
@@ -585,14 +633,18 @@ private fun SelfieStatusBadge(
585633

586634
@Composable
587635
private fun CaptureGuide(showCenteredShadow: Boolean) {
588-
val centeredShadowAlpha by animateFloatAsState(
589-
targetValue = if (showCenteredShadow) 1f else 0f,
590-
animationSpec = tween(
591-
durationMillis = CAPTURE_GUIDE_SHADOW_ANIMATION_TIME,
592-
easing = FastOutSlowInEasing
593-
),
594-
label = "centeredShadowAlpha"
595-
)
636+
val centeredShadowAlpha = remember { Animatable(0f) }
637+
638+
LaunchedEffect(showCenteredShadow) {
639+
centeredShadowAlpha.animateTo(
640+
targetValue = if (showCenteredShadow) 1f else 0f,
641+
animationSpec = tween(
642+
durationMillis = CAPTURE_GUIDE_SHADOW_ANIMATION_TIME,
643+
easing = FastOutSlowInEasing
644+
)
645+
)
646+
}
647+
596648
Canvas(
597649
modifier = Modifier
598650
.fillMaxSize()
@@ -603,12 +655,12 @@ private fun CaptureGuide(showCenteredShadow: Boolean) {
603655
}
604656

605657
val geometry = captureGuideGeometry()
606-
if (centeredShadowAlpha > 0f) {
658+
if (centeredShadowAlpha.value > 0f) {
607659
drawCenteredGuideShadow(
608660
center = geometry.center,
609661
horizontalRadius = geometry.horizontalRadius,
610662
verticalRadius = geometry.verticalRadius,
611-
opacity = centeredShadowAlpha
663+
opacity = centeredShadowAlpha.value
612664
)
613665
}
614666

0 commit comments

Comments
 (0)