Skip to content

Commit ada2297

Browse files
committedMar 10, 2025
Add mapper to support Modal Windows on android
1 parent ad8dfa2 commit ada2297

File tree

5 files changed

+78
-54
lines changed

5 files changed

+78
-54
lines changed
 

‎packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupport.kt

+3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ import com.datadog.reactnative.sessionreplay.mappers.ReactEditTextMapper
1414
import com.datadog.reactnative.sessionreplay.mappers.ReactNativeImageViewMapper
1515
import com.datadog.reactnative.sessionreplay.mappers.ReactTextMapper
1616
import com.datadog.reactnative.sessionreplay.mappers.ReactViewGroupMapper
17+
import com.datadog.reactnative.sessionreplay.mappers.ReactViewModalMapper
1718
import com.datadog.reactnative.sessionreplay.utils.text.TextViewUtils
1819
import com.facebook.react.views.image.ReactImageView
20+
import com.facebook.react.views.modal.ReactModalHostView
1921
import com.facebook.react.views.text.ReactTextView
2022
import com.facebook.react.views.textinput.ReactEditText
2123
import com.facebook.react.views.view.ReactViewGroup
@@ -34,6 +36,7 @@ internal class ReactNativeSessionReplayExtensionSupport(
3436
MapperTypeWrapper(ReactViewGroup::class.java, ReactViewGroupMapper()),
3537
MapperTypeWrapper(ReactTextView::class.java, ReactTextMapper(textViewUtils)),
3638
MapperTypeWrapper(ReactEditText::class.java, ReactEditTextMapper(textViewUtils)),
39+
MapperTypeWrapper(ReactModalHostView::class.java, ReactViewModalMapper()),
3740
)
3841
}
3942

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.datadog.reactnative.sessionreplay.mappers
2+
3+
import ReactViewBackgroundDrawableUtils
4+
import android.view.View
5+
import com.datadog.android.api.InternalLogger
6+
import com.datadog.android.sessionreplay.model.MobileSegment
7+
import com.datadog.android.sessionreplay.recorder.MappingContext
8+
import com.datadog.android.sessionreplay.recorder.mapper.BaseWireframeMapper
9+
import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
10+
import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter
11+
import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver
12+
import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver.resolveViewGlobalBounds
13+
import com.datadog.android.sessionreplay.utils.DefaultViewIdentifierResolver
14+
import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
15+
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
16+
17+
internal open class DefaultMapper<T: View>(
18+
private val drawableUtils: DrawableUtils =
19+
ReactViewBackgroundDrawableUtils()
20+
): BaseWireframeMapper<T>(
21+
viewIdentifierResolver = DefaultViewIdentifierResolver,
22+
colorStringFormatter = DefaultColorStringFormatter,
23+
viewBoundsResolver = DefaultViewBoundsResolver,
24+
drawableToColorMapper = DrawableToColorMapper.getDefault()
25+
) {
26+
override fun map(
27+
view: T,
28+
mappingContext: MappingContext,
29+
asyncJobStatusCallback: AsyncJobStatusCallback,
30+
internalLogger: InternalLogger
31+
): List<MobileSegment.Wireframe> {
32+
val pixelDensity = mappingContext.systemInformation.screenDensity
33+
val viewGlobalBounds = resolveViewGlobalBounds(view, pixelDensity)
34+
val backgroundDrawable = drawableUtils.getReactBackgroundFromDrawable(view.background)
35+
36+
// view.alpha is the value of the opacity prop on the js side
37+
val opacity = view.alpha
38+
39+
val (shapeStyle, border) =
40+
if (backgroundDrawable != null) {
41+
drawableUtils
42+
.resolveShapeAndBorder(backgroundDrawable, opacity, pixelDensity)
43+
} else {
44+
null to null
45+
}
46+
47+
return listOf(
48+
MobileSegment.Wireframe.ShapeWireframe(
49+
resolveViewId(view),
50+
viewGlobalBounds.x,
51+
viewGlobalBounds.y,
52+
viewGlobalBounds.width,
53+
viewGlobalBounds.height,
54+
shapeStyle = shapeStyle,
55+
border = border
56+
)
57+
)
58+
}
59+
}

‎packages/react-native-session-replay/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactViewGroupMapper.kt

+1-53
Original file line numberDiff line numberDiff line change
@@ -7,63 +7,11 @@
77
package com.datadog.reactnative.sessionreplay.mappers
88

99
import ReactViewBackgroundDrawableUtils
10-
import com.datadog.android.api.InternalLogger
11-
import com.datadog.android.sessionreplay.model.MobileSegment
12-
import com.datadog.android.sessionreplay.recorder.MappingContext
13-
import com.datadog.android.sessionreplay.recorder.mapper.BaseWireframeMapper
1410
import com.datadog.android.sessionreplay.recorder.mapper.TraverseAllChildrenMapper
15-
import com.datadog.android.sessionreplay.utils.AsyncJobStatusCallback
16-
import com.datadog.android.sessionreplay.utils.DefaultColorStringFormatter
17-
import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver
18-
import com.datadog.android.sessionreplay.utils.DefaultViewBoundsResolver.resolveViewGlobalBounds
19-
import com.datadog.android.sessionreplay.utils.DefaultViewIdentifierResolver
20-
import com.datadog.android.sessionreplay.utils.DrawableToColorMapper
2111
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
2212
import com.facebook.react.views.view.ReactViewGroup
2313

2414
internal class ReactViewGroupMapper(
2515
private val drawableUtils: DrawableUtils =
2616
ReactViewBackgroundDrawableUtils()
27-
) :
28-
BaseWireframeMapper<ReactViewGroup>(
29-
viewIdentifierResolver = DefaultViewIdentifierResolver,
30-
colorStringFormatter = DefaultColorStringFormatter,
31-
viewBoundsResolver = DefaultViewBoundsResolver,
32-
drawableToColorMapper = DrawableToColorMapper.getDefault()
33-
),
34-
TraverseAllChildrenMapper<ReactViewGroup> {
35-
36-
override fun map(
37-
view: ReactViewGroup,
38-
mappingContext: MappingContext,
39-
asyncJobStatusCallback: AsyncJobStatusCallback,
40-
internalLogger: InternalLogger
41-
): List<MobileSegment.Wireframe> {
42-
val pixelDensity = mappingContext.systemInformation.screenDensity
43-
val viewGlobalBounds = resolveViewGlobalBounds(view, pixelDensity)
44-
val backgroundDrawable = drawableUtils.getReactBackgroundFromDrawable(view.background)
45-
46-
// view.alpha is the value of the opacity prop on the js side
47-
val opacity = view.alpha
48-
49-
val (shapeStyle, border) =
50-
if (backgroundDrawable != null) {
51-
drawableUtils
52-
.resolveShapeAndBorder(backgroundDrawable, opacity, pixelDensity)
53-
} else {
54-
null to null
55-
}
56-
57-
return listOf(
58-
MobileSegment.Wireframe.ShapeWireframe(
59-
resolveViewId(view),
60-
viewGlobalBounds.x,
61-
viewGlobalBounds.y,
62-
viewGlobalBounds.width,
63-
viewGlobalBounds.height,
64-
shapeStyle = shapeStyle,
65-
border = border
66-
)
67-
)
68-
}
69-
}
17+
) : DefaultMapper<ReactViewGroup>(drawableUtils), TraverseAllChildrenMapper<ReactViewGroup>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.datadog.reactnative.sessionreplay.mappers
2+
3+
import ReactViewBackgroundDrawableUtils
4+
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
5+
import com.facebook.react.views.modal.ReactModalHostView
6+
7+
internal class ReactViewModalMapper(
8+
private val drawableUtils: DrawableUtils =
9+
ReactViewBackgroundDrawableUtils()
10+
) : DefaultMapper<ReactModalHostView>(drawableUtils)

‎packages/react-native-session-replay/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupportTest.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.datadog.reactnative.sessionreplay.mappers.ReactEditTextMapper
1111
import com.datadog.reactnative.sessionreplay.mappers.ReactNativeImageViewMapper
1212
import com.datadog.reactnative.sessionreplay.mappers.ReactTextMapper
1313
import com.datadog.reactnative.sessionreplay.mappers.ReactViewGroupMapper
14+
import com.datadog.reactnative.sessionreplay.mappers.ReactViewModalMapper
1415
import com.datadog.reactnative.sessionreplay.utils.text.TextViewUtils
1516
import com.facebook.react.bridge.NativeModule
1617
import com.facebook.react.bridge.ReactContext
@@ -62,7 +63,7 @@ internal class ReactNativeSessionReplayExtensionSupportTest {
6263
val customViewMappers = testedExtensionSupport.getCustomViewMappers()
6364

6465
// Then
65-
assertThat(customViewMappers).hasSize(4)
66+
assertThat(customViewMappers).hasSize(5)
6667

6768
assertThat(customViewMappers[0].getUnsafeMapper())
6869
.isInstanceOf(ReactNativeImageViewMapper::class.java)
@@ -75,5 +76,8 @@ internal class ReactNativeSessionReplayExtensionSupportTest {
7576

7677
assertThat(customViewMappers[3].getUnsafeMapper())
7778
.isInstanceOf(ReactEditTextMapper::class.java)
79+
80+
assertThat(customViewMappers[4].getUnsafeMapper())
81+
.isInstanceOf(ReactViewModalMapper::class.java)
7882
}
7983
}

0 commit comments

Comments
 (0)