Skip to content

Commit

Permalink
Resolve ShapeWireframe for ReactEditText BG drawable
Browse files Browse the repository at this point in the history
  • Loading branch information
marco-saia-datadog committed Dec 18, 2024
1 parent 53dca44 commit 2737ce9
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 93 deletions.
8 changes: 4 additions & 4 deletions packages/core/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,10 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compileOnly "com.squareup.okhttp3:okhttp:3.12.13"

implementation "com.datadoghq:dd-sdk-android-rum:2.14.0"
implementation "com.datadoghq:dd-sdk-android-logs:2.14.0"
implementation "com.datadoghq:dd-sdk-android-trace:2.14.0"
implementation "com.datadoghq:dd-sdk-android-webview:2.14.0"
implementation "com.datadoghq:dd-sdk-android-rum:2.16.1"
implementation "com.datadoghq:dd-sdk-android-logs:2.16.1"
implementation "com.datadoghq:dd-sdk-android-trace:2.16.1"
implementation "com.datadoghq:dd-sdk-android-webview:2.16.1"
implementation "com.google.code.gson:gson:2.10.0"
testImplementation "org.junit.platform:junit-platform-launcher:1.6.2"
testImplementation "org.junit.jupiter:junit-jupiter-api:5.6.2"
Expand Down
3 changes: 2 additions & 1 deletion packages/react-native-session-replay/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ dependencies {
api "com.facebook.react:react-android:$reactNativeVersion"
}
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "com.datadoghq:dd-sdk-android-session-replay:2.14.0"
implementation "com.datadoghq:dd-sdk-android-session-replay:2.16.1"
implementation "com.datadoghq:dd-sdk-android-internal:2.16.1"
implementation project(path: ':datadog_mobile-react-native')

testImplementation "org.junit.platform:junit-platform-launcher:1.6.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.datadog.android.api.InternalLogger
import com.datadog.android.sessionreplay.ExtensionSupport
import com.datadog.android.sessionreplay.MapperTypeWrapper
import com.datadog.android.sessionreplay.recorder.OptionSelectorDetector
import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
import com.datadog.reactnative.sessionreplay.mappers.ReactEditTextMapper
import com.datadog.reactnative.sessionreplay.mappers.ReactTextMapper
import com.datadog.reactnative.sessionreplay.mappers.ReactViewGroupMapper
Expand All @@ -24,6 +25,9 @@ internal class ReactNativeSessionReplayExtensionSupport(
private val reactContext: ReactContext,
private val logger: InternalLogger
) : ExtensionSupport {
override fun name(): String {
return ReactNativeSessionReplayExtensionSupport::class.java.simpleName
}

override fun getCustomViewMappers(): List<MapperTypeWrapper<*>> {
val uiManagerModule = getUiManagerModule()
Expand All @@ -35,10 +39,6 @@ internal class ReactNativeSessionReplayExtensionSupport(
)
}

override fun getOptionSelectorDetectors(): List<OptionSelectorDetector> {
return listOf()
}

@VisibleForTesting
internal fun getUiManagerModule(): UIManagerModule? {
return try {
Expand All @@ -54,6 +54,14 @@ internal class ReactNativeSessionReplayExtensionSupport(
}
}

override fun getOptionSelectorDetectors(): List<OptionSelectorDetector> {
return listOf()
}

override fun getCustomDrawableMapper(): List<DrawableToColorMapper> {
return emptyList()
}

internal companion object {
internal const val RESOLVE_UIMANAGERMODULE_ERROR = "Unable to resolve UIManagerModule"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import ReactViewBackgroundDrawableUtils
import android.view.Gravity
import android.widget.TextView
import androidx.annotation.VisibleForTesting
import com.datadog.android.internal.utils.densityNormalized
import com.datadog.android.sessionreplay.model.MobileSegment
import com.datadog.reactnative.sessionreplay.extensions.convertToDensityNormalized
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
import com.datadog.reactnative.sessionreplay.utils.ReflectionUtils
import com.datadog.reactnative.sessionreplay.utils.formatAsRgba
Expand Down Expand Up @@ -134,7 +134,7 @@ internal class ReactTextPropertiesResolver(
val fontFamily = getFontFamily(shadowNodeWrapper)
?: textWireframe.textStyle.family
val fontSize = getFontSize(shadowNodeWrapper)
?.convertToDensityNormalized(pixelsDensity)
?.densityNormalized(pixelsDensity)
?: textWireframe.textStyle.size
val fontColor = getTextColor(shadowNodeWrapper)
?: textWireframe.textStyle.color
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,70 +4,144 @@
* Copyright 2016-Present Datadog, Inc.
*/

package com.datadog.reactnative.sessionreplay.mappers
package com.datadog.reactnative.sessionreplay.mappers

import com.datadog.android.api.InternalLogger
import com.datadog.android.sessionreplay.model.MobileSegment
import com.datadog.android.sessionreplay.recorder.MappingContext
import com.datadog.android.sessionreplay.recorder.mapper.EditTextMapper
import com.datadog.android.sessionreplay.recorder.mapper.WireframeMapper
import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter
import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver
import com.datadog.android.sessionreplay.utils.DefaultViewIdentifierResolver
import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
import com.datadog.reactnative.sessionreplay.NoopTextPropertiesResolver
import com.datadog.reactnative.sessionreplay.ReactTextPropertiesResolver
import com.datadog.reactnative.sessionreplay.TextPropertiesResolver
import com.datadog.reactnative.sessionreplay.utils.TextViewUtils
import com.facebook.react.bridge.ReactContext
import com.facebook.react.uimanager.UIManagerModule
import com.facebook.react.views.textinput.ReactEditText
import ReactViewBackgroundDrawableUtils
import android.view.View
import com.datadog.android.api.InternalLogger
import com.datadog.android.sessionreplay.model.MobileSegment
import com.datadog.android.sessionreplay.recorder.MappingContext
import com.datadog.android.sessionreplay.recorder.mapper.BaseAsyncBackgroundWireframeMapper
import com.datadog.android.sessionreplay.recorder.mapper.EditTextMapper
import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter
import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver
import com.datadog.android.sessionreplay.utils.DefaultViewIdentifierResolver
import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
import com.datadog.android.sessionreplay.utils.GlobalBounds
import com.datadog.reactnative.sessionreplay.NoopTextPropertiesResolver
import com.datadog.reactnative.sessionreplay.ReactTextPropertiesResolver
import com.datadog.reactnative.sessionreplay.TextPropertiesResolver
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
import com.datadog.reactnative.sessionreplay.utils.TextViewUtils
import com.facebook.react.bridge.ReactContext
import com.facebook.react.uimanager.UIManagerModule
import com.facebook.react.views.image.ReactImageView
import com.facebook.react.views.textinput.ReactEditText

internal class ReactEditTextMapper(
private val reactTextPropertiesResolver: TextPropertiesResolver =
NoopTextPropertiesResolver(),
private val textViewUtils: TextViewUtils = TextViewUtils(),
): WireframeMapper<ReactEditText> {
private val reactTextPropertiesResolver: TextPropertiesResolver =
NoopTextPropertiesResolver(),
private val textViewUtils: TextViewUtils = TextViewUtils(),
): BaseAsyncBackgroundWireframeMapper<ReactEditText>(
viewIdentifierResolver = DefaultViewIdentifierResolver,
colorStringFormatter = DefaultColorStringFormatter,
viewBoundsResolver = DefaultViewBoundsResolver,
drawableToColorMapper = DrawableToColorMapper.getDefault(),
) {
private val drawableUtils = ReactViewBackgroundDrawableUtils()

private val editTextMapper = EditTextMapper(
viewIdentifierResolver = DefaultViewIdentifierResolver,
colorStringFormatter = DefaultColorStringFormatter,
viewBoundsResolver = DefaultViewBoundsResolver,
drawableToColorMapper = DrawableToColorMapper.getDefault(),
)
private val editTextMapper = EditTextMapper(
viewIdentifierResolver = viewIdentifierResolver,
colorStringFormatter = colorStringFormatter,
viewBoundsResolver = viewBoundsResolver,
drawableToColorMapper = drawableToColorMapper,
)

internal constructor(
reactContext: ReactContext,
uiManagerModule: UIManagerModule?
): this(
reactTextPropertiesResolver = if (uiManagerModule == null) {
NoopTextPropertiesResolver()
} else {
ReactTextPropertiesResolver(
reactContext = reactContext,
uiManagerModule = uiManagerModule
)
}
)

override fun map(
view: ReactEditText,
mappingContext: MappingContext,
asyncJobStatusCallback: AsyncJobStatusCallback,
internalLogger: InternalLogger
): List<MobileSegment.Wireframe> {
val bgWireframes = mutableListOf<MobileSegment.Wireframe>().apply {
addAll(super.map(
view,
mappingContext,
asyncJobStatusCallback,
internalLogger
))
}

bgWireframes += editTextMapper.map(
view = view,
mappingContext = mappingContext,
asyncJobStatusCallback = asyncJobStatusCallback,
internalLogger = internalLogger
).filterNot { it is MobileSegment.Wireframe.ImageWireframe }

return textViewUtils.mapTextViewToWireframes(
wireframes = bgWireframes,
view = view,
mappingContext = mappingContext,
reactTextPropertiesResolver = reactTextPropertiesResolver
)
}

internal constructor(
reactContext: ReactContext,
uiManagerModule: UIManagerModule?
): this(
reactTextPropertiesResolver = if (uiManagerModule == null) {
NoopTextPropertiesResolver()
} else {
ReactTextPropertiesResolver(
reactContext = reactContext,
uiManagerModule = uiManagerModule
)
}
)
override fun map(
view: ReactEditText,
mappingContext: MappingContext,
asyncJobStatusCallback: AsyncJobStatusCallback,
internalLogger: InternalLogger
): List<MobileSegment.Wireframe> {
val wireframes = editTextMapper.map(
view = view,
mappingContext = mappingContext,
asyncJobStatusCallback = asyncJobStatusCallback,
internalLogger = internalLogger
)
@Suppress("FunctionMaxLength")
override fun resolveBackgroundAsImageWireframe(
view: View,
bounds: GlobalBounds,
width: Int,
height: Int,
mappingContext: MappingContext,
asyncJobStatusCallback: AsyncJobStatusCallback
): MobileSegment.Wireframe? {
if (view !is ReactImageView) {
return super.resolveBackgroundAsImageWireframe(
view,
bounds,
width,
height,
mappingContext,
asyncJobStatusCallback
)
}

return textViewUtils.mapTextViewToWireframes(
wireframes = wireframes,
view = view,
mappingContext = mappingContext,
reactTextPropertiesResolver = reactTextPropertiesResolver
)
}
}
val bgDrawable = drawableUtils.getReactBackgroundFromDrawable(view.background)
?: return null

val density = mappingContext.systemInformation.screenDensity

val identifier = viewIdentifierResolver.resolveChildUniqueIdentifier(
view,
"drawable0"
) ?: return null

val globalBounds = viewBoundsResolver.resolveViewGlobalBounds(
view,
density
)

val (shape, border) = drawableUtils.resolveShapeAndBorder(
bgDrawable,
view.alpha,
mappingContext.systemInformation.screenDensity
)

return MobileSegment.Wireframe.ShapeWireframe(
identifier,
globalBounds.x,
globalBounds.y,
globalBounds.width,
globalBounds.height,
border = border,
shapeStyle = shape
)
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ internal abstract class DrawableUtils(
): Pair<MobileSegment.ShapeStyle?, MobileSegment.ShapeBorder?>

internal abstract fun getReactBackgroundFromDrawable(drawable: Drawable?): Drawable?
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import android.graphics.drawable.Drawable
import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
import com.datadog.android.internal.utils.densityNormalized
import com.datadog.android.sessionreplay.model.MobileSegment
import com.datadog.reactnative.sessionreplay.extensions.convertToDensityNormalized
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
import com.datadog.reactnative.sessionreplay.utils.formatAsRgba
import com.facebook.react.common.annotations.UnstableReactNativeAPI
Expand Down Expand Up @@ -81,7 +81,7 @@ internal class ReactViewBackgroundDrawableUtils : DrawableUtils() {
pixelDensity: Float
): MobileSegment.ShapeBorder {
val borderWidth =
backgroundDrawable.fullBorderWidth.toLong().convertToDensityNormalized(pixelDensity)
backgroundDrawable.fullBorderWidth.toLong().densityNormalized(pixelDensity)
val borderColor = formatAsRgba(backgroundDrawable.getBorderColor(Spacing.ALL))

return MobileSegment.ShapeBorder(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import android.graphics.drawable.Drawable
import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.LayerDrawable
import com.datadog.android.internal.utils.densityNormalized
import com.datadog.android.sessionreplay.model.MobileSegment
import com.datadog.reactnative.sessionreplay.extensions.convertToDensityNormalized
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
import com.datadog.reactnative.sessionreplay.utils.formatAsRgba
import com.facebook.react.uimanager.Spacing
Expand All @@ -22,7 +22,7 @@ internal class ReactViewBackgroundDrawableUtils() : DrawableUtils() {
val cornerRadius = drawable
.fullBorderRadius
.toLong()
.convertToDensityNormalized(pixelDensity)
.densityNormalized(pixelDensity)

val backgroundColor = getBackgroundColor(drawable)
val colorHexString = if (backgroundColor != null) {
Expand Down Expand Up @@ -64,7 +64,7 @@ internal class ReactViewBackgroundDrawableUtils() : DrawableUtils() {
pixelDensity: Float
): MobileSegment.ShapeBorder {
val borderWidth =
backgroundDrawable.fullBorderWidth.toLong().convertToDensityNormalized(pixelDensity)
backgroundDrawable.fullBorderWidth.toLong().densityNormalized(pixelDensity)
val borderColor = formatAsRgba(backgroundDrawable.getBorderColor(Spacing.ALL))

return MobileSegment.ShapeBorder(
Expand Down

0 comments on commit 2737ce9

Please sign in to comment.