Skip to content

Commit

Permalink
Make parent opacity override child opacity
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanmos committed Nov 28, 2023
1 parent aa3f4ca commit b470622
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,29 @@

package com.datadog.reactnative.sessionreplay

import androidx.annotation.VisibleForTesting
import com.facebook.react.views.view.ReactViewGroup

private const val ALPHA_CODE_LENGTH: Int = 2
private const val HEX_RADIX: Int = 16
private const val OPAQUE_ALPHA_VALUE: Int = 255
private const val HEX_COLOR_INCLUDING_ALPHA_LENGTH: Int = 8

internal fun resolveAlphaValue(viewAlpha: Float, backgroundColor: Int): Int {
internal fun resolveAlpha(opacity: Float, backgroundColor: Int?): Int {
// must not be toHexString because we'll lose the sign bit
val bgColorAsHexCode = backgroundColor.toString(HEX_RADIX)
var pct = viewAlpha
val bgColorAsHexCode = backgroundColor?.toString(HEX_RADIX)
var opacityPercentage = opacity

if (bgColorAsHexCode.length == HEX_COLOR_INCLUDING_ALPHA_LENGTH) {
if (bgColorAsHexCode?.length == HEX_COLOR_INCLUDING_ALPHA_LENGTH) {
val opacityCode = bgColorAsHexCode.take(ALPHA_CODE_LENGTH)
pct = alphaCodeToPct(opacityCode)
opacityPercentage = alphaCodeToPct(opacityCode)
}

return (pct * OPAQUE_ALPHA_VALUE).toInt()
return (opacityPercentage * OPAQUE_ALPHA_VALUE).toInt()
}

private fun alphaCodeToPct(hexAlpha: String): Float {
@VisibleForTesting
internal fun alphaCodeToPct(hexAlpha: String): Float {
return try {
val alphaDecimal = hexAlpha.toInt(HEX_RADIX)
(alphaDecimal / 255.0).toFloat()
Expand All @@ -33,3 +37,15 @@ private fun alphaCodeToPct(hexAlpha: String): Float {
1f
}
}

internal fun resolveOpacity(view: ReactViewGroup, currentOpacity: Float): Float {
return if (view.alpha == 0f) {
0f
} else {
if (view.parent != null && view.parent is ReactViewGroup) {
resolveOpacity(view.parent as ReactViewGroup, Math.min(view.alpha, currentOpacity))
} else {
Math.min(view.alpha, currentOpacity)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package com.datadog.reactnative.sessionreplay

import android.annotation.SuppressLint
import android.graphics.Color
import com.datadog.android.sessionreplay.internal.AsyncJobStatusCallback
import com.datadog.android.sessionreplay.internal.recorder.MappingContext
import com.datadog.android.sessionreplay.internal.recorder.mapper.BaseWireframeMapper
Expand All @@ -32,24 +33,32 @@ internal class ReactViewGroupMapper :
)

val pixelDensity = mappingContext.systemInformation.screenDensity
val backgroundDrawable = view.background as? ReactViewBackgroundDrawable
val backgroundDrawable = view.background as? ReactViewBackgroundDrawable ?: return emptyList()

val backgroundColor = backgroundDrawable?.color ?: 0
val viewAlpha = resolveAlphaValue(view.alpha, backgroundColor)
val backgroundColor = view.backgroundColor
if (backgroundColor == Color.TRANSPARENT) {
return emptyList()
}
val opacity = resolveOpacity(view, view.alpha)

if (viewAlpha == 0) {
// view.alpha is the value of the opacity prop on the js side
// this should override the alpha value of the background color if it is explicitly 0
if (opacity == 0f) {
return emptyList()
}

val color = colorAndAlphaAsStringHexa(
val viewAlpha = resolveAlpha(opacity, backgroundColor)

val backgroundColorAndAlpha = colorAndAlphaAsStringHexa(
color = backgroundColor,
alphaAsHexa = viewAlpha
)

val (shapeStyle, border) = resolveRNShapeStyleAndBorder(
backgroundDrawable = backgroundDrawable,
viewAlpha = viewAlpha,
viewColor = color,
viewColor = backgroundColorAndAlpha,
opacity = opacity,
pixelDensity = pixelDensity
)

Expand All @@ -66,12 +75,11 @@ internal class ReactViewGroupMapper :
)
}



private fun resolveRNShapeStyleAndBorder(
backgroundDrawable: ReactViewBackgroundDrawable?,
viewAlpha: Int,
viewColor: String,
opacity: Float,
pixelDensity: Float
):
Pair<MobileSegment.ShapeStyle?, MobileSegment.ShapeBorder?> {
Expand All @@ -82,7 +90,7 @@ internal class ReactViewGroupMapper :
) to null
} else {
val cornerRadius = backgroundDrawable.fullBorderRadius
val borderColor = resolveBorderColor(backgroundDrawable)
val borderColor = resolveBorderColor(backgroundDrawable, opacity)
val borderWidth = backgroundDrawable.fullBorderWidth
val cornerRadiusDp = cornerRadius.toLong().convertToDensityNormalized(pixelDensity)

Expand All @@ -97,9 +105,9 @@ internal class ReactViewGroupMapper :
}
}

private fun resolveBorderColor(backgroundDrawable: ReactViewBackgroundDrawable): String {
private fun resolveBorderColor(backgroundDrawable: ReactViewBackgroundDrawable, opacity: Float): String {
val borderColor = backgroundDrawable.getBorderColor(Spacing.ALL)
val alpha = resolveAlphaValue(1f, borderColor)
val alpha = resolveAlpha(opacity, borderColor)
return colorAndAlphaAsStringHexa(borderColor, alpha)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

package com.datadog.reactnative.sessionreplay

import android.graphics.Color
import androidx.annotation.Size
import fr.xgouchet.elmyr.junit5.ForgeExtension
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
Expand All @@ -27,8 +25,9 @@ internal class ColorUtilsTest {
@Test
fun `M use default alpha W resolveAlphaValue { color without opacity }`() {
// When
val alphaValue = resolveAlphaValue(0.1f, 0x000000)
val alphaValue = resolveAlpha(0.1f, 0x000000)

// 0.1f = 10% opacity -> 10% of 255 is 25
// Then
assertThat(alphaValue)
.isEqualTo(25)
Expand All @@ -40,10 +39,24 @@ internal class ColorUtilsTest {
val color = 1717960806

// When
val alphaValue = resolveAlphaValue(0.1f, color)
val alphaValue = resolveAlpha(0.1f, color)

// decimal color 1717960806 translates to hex 66660066
// 66 being the hex alpha, which is 40% opacity -> 40% of 255 is 102
// Then
assertThat(alphaValue).isEqualTo(102)
}

@Test
fun `M return alpha of 1f W alphaCodeToPct { NumberFormatException }`() {
// Given
val color = "not a number"

// When
val alphaValue = alphaCodeToPct(color)

// Then
assertThat(alphaValue)
.isEqualTo(102)
.isEqualTo(1f)
}
}

0 comments on commit b470622

Please sign in to comment.