@datadog/mobile-react-native-session-replay 2.6.0 → 2.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +52 -1
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/DdSessionReplayImplementation.kt +5 -5
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupport.kt +5 -29
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/ShadowNodeWrapper.kt +2 -2
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactEditTextMapper.kt +3 -26
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/mappers/ReactTextMapper.kt +3 -25
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/text/FabricTextViewUtils.kt +74 -0
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/text/LegacyTextViewUtils.kt +118 -0
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/{ReactTextPropertiesResolver.kt → utils/text/TextViewUtils.kt} +60 -96
- package/android/src/rn75/kotlin/com/datadog/reactnative/sessionreplay/extensions/LengthPercentageExt.kt +1 -2
- package/android/src/rn75/kotlin/com/datadog/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.kt +1 -3
- package/android/src/rn76/kotlin/com/datadog/reactnative/sessionreplay/extensions/LengthPercentageExt.kt +1 -1
- package/android/src/rn76/kotlin/com/datadog/reactnative/sessionreplay/utils/ReactViewBackgroundDrawableUtils.kt +1 -3
- package/android/src/rnlegacy/kotlin/com.datadog.reactnative.sessionreplay/utils/ReactViewBackgroundDrawableUtils.kt +2 -7
- package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/ReactNativeSessionReplayExtensionSupportTest.kt +3 -17
- package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/{ReactTextPropertiesResolverTest.kt → utils/text/TextViewUtilsTest.kt} +171 -38
- package/ios/Sources/DdSessionReplay.mm +4 -4
- package/ios/Sources/DdSessionReplayImplementation.swift +13 -3
- package/ios/Sources/RCTFabricWrapper.h +13 -0
- package/ios/Sources/RCTFabricWrapper.mm +120 -0
- package/ios/Sources/RCTTextPropertiesWrapper.h +23 -0
- package/ios/Sources/RCTTextPropertiesWrapper.mm +28 -0
- package/ios/Sources/RCTTextViewRecorder.swift +69 -49
- package/ios/Sources/RCTVersion.h +8 -0
- package/lib/commonjs/SessionReplay.js +1 -1
- package/lib/commonjs/SessionReplay.js.map +1 -1
- package/lib/module/SessionReplay.js +1 -1
- package/lib/module/SessionReplay.js.map +1 -1
- package/package.json +6 -3
- package/scripts/set-ios-rn-version.js +47 -0
- package/src/SessionReplay.ts +1 -1
- package/src/__tests__/SessionReplay.test.ts +1 -1
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/NoopTextPropertiesResolver.kt +0 -22
- package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt +0 -40
- package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt +0 -109
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
package com.datadog.reactnative.sessionreplay.utils.text
|
|
2
|
+
|
|
3
|
+
import android.widget.TextView
|
|
4
|
+
import androidx.annotation.VisibleForTesting
|
|
5
|
+
import com.datadog.android.api.InternalLogger
|
|
6
|
+
import com.datadog.android.internal.utils.densityNormalized
|
|
7
|
+
import com.datadog.android.sessionreplay.model.MobileSegment
|
|
8
|
+
import com.datadog.reactnative.sessionreplay.ShadowNodeWrapper
|
|
9
|
+
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
|
|
10
|
+
import com.datadog.reactnative.sessionreplay.utils.ReflectionUtils
|
|
11
|
+
import com.datadog.reactnative.sessionreplay.utils.formatAsRgba
|
|
12
|
+
import com.facebook.react.bridge.ReactContext
|
|
13
|
+
import com.facebook.react.uimanager.UIManagerModule
|
|
14
|
+
import com.facebook.react.views.text.TextAttributes
|
|
15
|
+
import java.util.Locale
|
|
16
|
+
|
|
17
|
+
internal class LegacyTextViewUtils(
|
|
18
|
+
private val reactContext: ReactContext,
|
|
19
|
+
private val logger: InternalLogger,
|
|
20
|
+
private val reflectionUtils: ReflectionUtils,
|
|
21
|
+
drawableUtils: DrawableUtils,
|
|
22
|
+
) : TextViewUtils(reactContext, drawableUtils) {
|
|
23
|
+
|
|
24
|
+
private val uiManager: UIManagerModule? by lazy {
|
|
25
|
+
getUiManagerModule()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override fun resolveTextStyle(
|
|
29
|
+
textWireframe: MobileSegment.Wireframe.TextWireframe,
|
|
30
|
+
pixelsDensity: Float,
|
|
31
|
+
view: TextView,
|
|
32
|
+
): MobileSegment.TextStyle? {
|
|
33
|
+
val shadowNodeWrapper: ShadowNodeWrapper =
|
|
34
|
+
ShadowNodeWrapper.getShadowNodeWrapper(
|
|
35
|
+
reactContext = reactContext,
|
|
36
|
+
uiManagerModule = uiManager,
|
|
37
|
+
reflectionUtils = reflectionUtils,
|
|
38
|
+
viewId = view.id,
|
|
39
|
+
) ?: return null
|
|
40
|
+
|
|
41
|
+
val fontFamily = getFontFamily(shadowNodeWrapper) ?: textWireframe.textStyle.family
|
|
42
|
+
|
|
43
|
+
val fontSize = getFontSize(shadowNodeWrapper)?.densityNormalized(pixelsDensity) ?: textWireframe.textStyle.size
|
|
44
|
+
|
|
45
|
+
val fontColor = getTextColor(shadowNodeWrapper) ?: textWireframe.textStyle.color
|
|
46
|
+
|
|
47
|
+
return MobileSegment.TextStyle(
|
|
48
|
+
family = fontFamily,
|
|
49
|
+
size = fontSize,
|
|
50
|
+
color = fontColor,
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private fun getTextColor(shadowNodeWrapper: ShadowNodeWrapper?): String? {
|
|
55
|
+
if (shadowNodeWrapper == null) return null
|
|
56
|
+
|
|
57
|
+
val isColorSet =
|
|
58
|
+
shadowNodeWrapper
|
|
59
|
+
.getDeclaredShadowNodeField(IS_COLOR_SET_FIELD_NAME) as Boolean?
|
|
60
|
+
|
|
61
|
+
if (isColorSet != true) {
|
|
62
|
+
// Improvement: get default text color if different from black
|
|
63
|
+
return "#000000FF"
|
|
64
|
+
}
|
|
65
|
+
val resolvedColor =
|
|
66
|
+
shadowNodeWrapper
|
|
67
|
+
.getDeclaredShadowNodeField(COLOR_FIELD_NAME) as Int?
|
|
68
|
+
if (resolvedColor != null) {
|
|
69
|
+
return formatAsRgba(resolvedColor)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
private fun getFontSize(shadowNodeWrapper: ShadowNodeWrapper?): Long? {
|
|
76
|
+
if (shadowNodeWrapper == null) return null
|
|
77
|
+
|
|
78
|
+
val textAttributes =
|
|
79
|
+
shadowNodeWrapper
|
|
80
|
+
.getDeclaredShadowNodeField(TEXT_ATTRIBUTES_FIELD_NAME) as? TextAttributes?
|
|
81
|
+
if (textAttributes != null) {
|
|
82
|
+
return textAttributes.effectiveFontSize.toLong()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return null
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private fun getFontFamily(shadowNodeWrapper: ShadowNodeWrapper?): String? {
|
|
89
|
+
if (shadowNodeWrapper == null) return null
|
|
90
|
+
|
|
91
|
+
val fontFamily =
|
|
92
|
+
shadowNodeWrapper
|
|
93
|
+
.getDeclaredShadowNodeField(FONT_FAMILY_FIELD_NAME) as? String
|
|
94
|
+
|
|
95
|
+
if (fontFamily != null) {
|
|
96
|
+
return resolveFontFamily(fontFamily.lowercase(Locale.US))
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return null
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// store to avoid calling it multiple times
|
|
103
|
+
@VisibleForTesting
|
|
104
|
+
internal fun getUiManagerModule(): UIManagerModule? {
|
|
105
|
+
return try {
|
|
106
|
+
reactContext.getNativeModule(UIManagerModule::class.java)
|
|
107
|
+
} catch (e: IllegalStateException) {
|
|
108
|
+
logger.log(
|
|
109
|
+
level = InternalLogger.Level.WARN,
|
|
110
|
+
targets = listOf(InternalLogger.Target.MAINTAINER, InternalLogger.Target.TELEMETRY),
|
|
111
|
+
messageBuilder = { RESOLVE_UIMANAGERMODULE_ERROR },
|
|
112
|
+
throwable = e,
|
|
113
|
+
)
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
@@ -1,33 +1,42 @@
|
|
|
1
|
-
|
|
2
|
-
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
3
|
-
* This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
4
|
-
* Copyright 2016-Present Datadog, Inc.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
package com.datadog.reactnative.sessionreplay
|
|
1
|
+
package com.datadog.reactnative.sessionreplay.utils.text
|
|
8
2
|
|
|
9
3
|
import ReactViewBackgroundDrawableUtils
|
|
10
4
|
import android.view.Gravity
|
|
11
5
|
import android.widget.TextView
|
|
12
6
|
import androidx.annotation.VisibleForTesting
|
|
13
|
-
import com.datadog.android.
|
|
7
|
+
import com.datadog.android.api.InternalLogger
|
|
14
8
|
import com.datadog.android.sessionreplay.model.MobileSegment
|
|
9
|
+
import com.datadog.android.sessionreplay.recorder.MappingContext
|
|
10
|
+
import com.datadog.reactnative.sessionreplay.BuildConfig
|
|
15
11
|
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
|
|
16
12
|
import com.datadog.reactnative.sessionreplay.utils.ReflectionUtils
|
|
17
|
-
import com.datadog.reactnative.sessionreplay.utils.formatAsRgba
|
|
18
13
|
import com.facebook.react.bridge.ReactContext
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
30
|
-
|
|
14
|
+
|
|
15
|
+
internal abstract class TextViewUtils(private val reactContext: ReactContext, private val drawableUtils: DrawableUtils) {
|
|
16
|
+
fun mapTextViewToWireframes(
|
|
17
|
+
wireframes: List<MobileSegment.Wireframe>,
|
|
18
|
+
view: TextView,
|
|
19
|
+
mappingContext: MappingContext,
|
|
20
|
+
): List<MobileSegment.Wireframe> {
|
|
21
|
+
val result = mutableListOf<MobileSegment.Wireframe>()
|
|
22
|
+
val pixelDensity = mappingContext.systemInformation.screenDensity
|
|
23
|
+
|
|
24
|
+
for (originalWireframe in wireframes) {
|
|
25
|
+
if (originalWireframe !is MobileSegment.Wireframe.TextWireframe) {
|
|
26
|
+
result.add(originalWireframe)
|
|
27
|
+
} else {
|
|
28
|
+
result.add(addReactNativeProperties(
|
|
29
|
+
originalWireframe = originalWireframe,
|
|
30
|
+
view = view,
|
|
31
|
+
pixelDensity = pixelDensity,
|
|
32
|
+
))
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return result
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fun addReactNativeProperties(
|
|
31
40
|
originalWireframe: MobileSegment.Wireframe.TextWireframe,
|
|
32
41
|
view: TextView,
|
|
33
42
|
pixelDensity: Float,
|
|
@@ -59,25 +68,17 @@ internal class ReactTextPropertiesResolver(
|
|
|
59
68
|
)
|
|
60
69
|
}
|
|
61
70
|
|
|
62
|
-
|
|
71
|
+
|
|
72
|
+
protected fun resolveTextStyleAndPosition(
|
|
63
73
|
originalWireframe: MobileSegment.Wireframe.TextWireframe,
|
|
64
74
|
view: TextView,
|
|
65
|
-
pixelDensity: Float
|
|
66
|
-
):
|
|
67
|
-
Pair<MobileSegment.TextStyle, MobileSegment.TextPosition>? {
|
|
68
|
-
|
|
75
|
+
pixelDensity: Float
|
|
76
|
+
): Pair<MobileSegment.TextStyle, MobileSegment.TextPosition>? {
|
|
69
77
|
if (!reactContext.hasActiveReactInstance()) {
|
|
70
78
|
return null
|
|
71
79
|
}
|
|
72
80
|
|
|
73
|
-
val
|
|
74
|
-
ShadowNodeWrapper.getShadowNodeWrapper(
|
|
75
|
-
reactContext = reactContext,
|
|
76
|
-
uiManagerModule = uiManagerModule,
|
|
77
|
-
reflectionUtils = reflectionUtils,
|
|
78
|
-
viewId = view.id) ?: return null
|
|
79
|
-
|
|
80
|
-
val textStyle = resolveTextStyle(originalWireframe, pixelDensity, shadowNodeWrapper)
|
|
81
|
+
val textStyle = resolveTextStyle(originalWireframe, pixelDensity, view) ?: return null
|
|
81
82
|
val alignment = resolveTextAlignment(view, originalWireframe)
|
|
82
83
|
|
|
83
84
|
val textPosition = MobileSegment.TextPosition(
|
|
@@ -88,7 +89,7 @@ internal class ReactTextPropertiesResolver(
|
|
|
88
89
|
return textStyle to textPosition
|
|
89
90
|
}
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
protected fun resolveShapeStyleAndBorder(
|
|
92
93
|
view: TextView,
|
|
93
94
|
pixelDensity: Float,
|
|
94
95
|
): Pair<MobileSegment.ShapeStyle?, MobileSegment.ShapeBorder?>? {
|
|
@@ -105,7 +106,7 @@ internal class ReactTextPropertiesResolver(
|
|
|
105
106
|
return shapeStyle to border
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
protected fun resolveTextAlignment(
|
|
109
110
|
view: TextView,
|
|
110
111
|
textWireframe: MobileSegment.Wireframe.TextWireframe
|
|
111
112
|
): MobileSegment.Alignment {
|
|
@@ -126,64 +127,7 @@ internal class ReactTextPropertiesResolver(
|
|
|
126
127
|
)
|
|
127
128
|
}
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
textWireframe: MobileSegment.Wireframe.TextWireframe,
|
|
131
|
-
pixelsDensity: Float,
|
|
132
|
-
shadowNodeWrapper: ShadowNodeWrapper
|
|
133
|
-
): MobileSegment.TextStyle {
|
|
134
|
-
val fontFamily = getFontFamily(shadowNodeWrapper)
|
|
135
|
-
?: textWireframe.textStyle.family
|
|
136
|
-
val fontSize = getFontSize(shadowNodeWrapper)
|
|
137
|
-
?.densityNormalized(pixelsDensity)
|
|
138
|
-
?: textWireframe.textStyle.size
|
|
139
|
-
val fontColor = getTextColor(shadowNodeWrapper)
|
|
140
|
-
?: textWireframe.textStyle.color
|
|
141
|
-
|
|
142
|
-
return MobileSegment.TextStyle(
|
|
143
|
-
family = fontFamily,
|
|
144
|
-
size = fontSize,
|
|
145
|
-
color = fontColor
|
|
146
|
-
)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
private fun getTextColor(shadowNodeWrapper: ShadowNodeWrapper): String? {
|
|
150
|
-
val isColorSet = shadowNodeWrapper
|
|
151
|
-
.getDeclaredShadowNodeField(IS_COLOR_SET_FIELD_NAME) as Boolean?
|
|
152
|
-
if (isColorSet != true) {
|
|
153
|
-
// Improvement: get default text color if different from black
|
|
154
|
-
return "#000000FF"
|
|
155
|
-
}
|
|
156
|
-
val resolvedColor = shadowNodeWrapper
|
|
157
|
-
.getDeclaredShadowNodeField(COLOR_FIELD_NAME) as Int?
|
|
158
|
-
if (resolvedColor != null) {
|
|
159
|
-
return formatAsRgba(resolvedColor)
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
return null
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
private fun getFontSize(shadowNodeWrapper: ShadowNodeWrapper): Long? {
|
|
166
|
-
val textAttributes = shadowNodeWrapper
|
|
167
|
-
.getDeclaredShadowNodeField(TEXT_ATTRIBUTES_FIELD_NAME) as? TextAttributes?
|
|
168
|
-
if (textAttributes != null) {
|
|
169
|
-
return textAttributes.effectiveFontSize.toLong()
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return null
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private fun getFontFamily(shadowNodeWrapper: ShadowNodeWrapper): String? {
|
|
176
|
-
val fontFamily = shadowNodeWrapper
|
|
177
|
-
.getDeclaredShadowNodeField(FONT_FAMILY_FIELD_NAME) as? String
|
|
178
|
-
|
|
179
|
-
if (fontFamily != null) {
|
|
180
|
-
return resolveFontFamily(fontFamily.lowercase(Locale.US))
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return null
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
private fun resolveFontFamily(typefaceName: String): String =
|
|
130
|
+
protected fun resolveFontFamily(typefaceName: String): String =
|
|
187
131
|
when (typefaceName) {
|
|
188
132
|
ROBOTO_TYPEFACE_NAME -> SANS_SERIF_FAMILY_NAME
|
|
189
133
|
MONOSPACE_FAMILY_NAME -> MONOSPACE_FAMILY_NAME
|
|
@@ -191,16 +135,36 @@ internal class ReactTextPropertiesResolver(
|
|
|
191
135
|
else -> SANS_SERIF_FAMILY_NAME
|
|
192
136
|
}
|
|
193
137
|
|
|
138
|
+
protected abstract fun resolveTextStyle( textWireframe: MobileSegment.Wireframe.TextWireframe,
|
|
139
|
+
pixelsDensity: Float,
|
|
140
|
+
view: TextView
|
|
141
|
+
): MobileSegment.TextStyle?
|
|
142
|
+
|
|
194
143
|
@VisibleForTesting
|
|
195
|
-
|
|
144
|
+
companion object {
|
|
196
145
|
internal const val TEXT_ATTRIBUTES_FIELD_NAME = "mTextAttributes"
|
|
197
146
|
internal const val FONT_FAMILY_FIELD_NAME = "mFontFamily"
|
|
198
147
|
internal const val COLOR_FIELD_NAME = "mColor"
|
|
199
148
|
internal const val IS_COLOR_SET_FIELD_NAME = "mIsColorSet"
|
|
149
|
+
internal const val SPANNED_FIELD_NAME = "mSpanned"
|
|
200
150
|
|
|
201
151
|
private const val ROBOTO_TYPEFACE_NAME = "roboto"
|
|
202
152
|
private const val SERIF_FAMILY_NAME = "serif"
|
|
203
153
|
private const val SANS_SERIF_FAMILY_NAME = "roboto, sans-serif"
|
|
204
154
|
internal const val MONOSPACE_FAMILY_NAME = "monospace"
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
internal const val RESOLVE_UIMANAGERMODULE_ERROR = "Unable to resolve UIManagerModule"
|
|
158
|
+
internal const val RESOLVE_FABRICFIELD_ERROR = "Unable to resolve field from fabric view"
|
|
159
|
+
internal const val NULL_FABRICFIELD_ERROR = "Null value found when trying to resolve field from fabric view"
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
fun create(reactContext: ReactContext, logger: InternalLogger): TextViewUtils {
|
|
163
|
+
return when (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
|
|
164
|
+
true -> FabricTextViewUtils(reactContext, logger, ReactViewBackgroundDrawableUtils())
|
|
165
|
+
false -> LegacyTextViewUtils(reactContext, logger, ReflectionUtils(), ReactViewBackgroundDrawableUtils())
|
|
166
|
+
}
|
|
167
|
+
}
|
|
205
168
|
}
|
|
206
|
-
|
|
169
|
+
|
|
170
|
+
}
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import android.graphics.drawable.Drawable
|
|
7
7
|
import android.graphics.drawable.InsetDrawable
|
|
8
8
|
import android.graphics.drawable.LayerDrawable
|
|
9
|
-
import com.datadog.android.internal.utils.densityNormalized
|
|
10
9
|
import com.datadog.android.sessionreplay.model.MobileSegment
|
|
11
10
|
import com.datadog.reactnative.sessionreplay.extensions.getRadius
|
|
12
11
|
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
|
|
@@ -85,8 +84,7 @@ internal class ReactViewBackgroundDrawableUtils : DrawableUtils() {
|
|
|
85
84
|
backgroundDrawable: CSSBackgroundDrawable,
|
|
86
85
|
pixelDensity: Float
|
|
87
86
|
): MobileSegment.ShapeBorder {
|
|
88
|
-
val borderWidth =
|
|
89
|
-
backgroundDrawable.fullBorderWidth.toLong().densityNormalized(pixelDensity)
|
|
87
|
+
val borderWidth = (backgroundDrawable.fullBorderWidth / pixelDensity).toLong()
|
|
90
88
|
val borderColor = formatAsRgba(backgroundDrawable.getBorderColor(Spacing.ALL))
|
|
91
89
|
|
|
92
90
|
return MobileSegment.ShapeBorder(
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
import android.graphics.drawable.Drawable
|
|
7
7
|
import android.graphics.drawable.InsetDrawable
|
|
8
8
|
import android.graphics.drawable.LayerDrawable
|
|
9
|
-
import com.datadog.android.internal.utils.densityNormalized
|
|
10
9
|
import com.datadog.android.sessionreplay.model.MobileSegment
|
|
11
10
|
import com.datadog.reactnative.sessionreplay.extensions.getRadius
|
|
12
11
|
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
|
|
@@ -85,8 +84,7 @@ internal class ReactViewBackgroundDrawableUtils : DrawableUtils() {
|
|
|
85
84
|
backgroundDrawable: CSSBackgroundDrawable,
|
|
86
85
|
pixelDensity: Float
|
|
87
86
|
): MobileSegment.ShapeBorder {
|
|
88
|
-
val borderWidth =
|
|
89
|
-
backgroundDrawable.fullBorderWidth.toLong().densityNormalized(pixelDensity)
|
|
87
|
+
val borderWidth = (backgroundDrawable.fullBorderWidth / pixelDensity).toLong()
|
|
90
88
|
val borderColor = formatAsRgba(backgroundDrawable.getBorderColor(Spacing.ALL))
|
|
91
89
|
|
|
92
90
|
return MobileSegment.ShapeBorder(
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import android.graphics.drawable.Drawable
|
|
2
2
|
import android.graphics.drawable.InsetDrawable
|
|
3
3
|
import android.graphics.drawable.LayerDrawable
|
|
4
|
-
import com.datadog.android.internal.utils.densityNormalized
|
|
5
4
|
import com.datadog.android.sessionreplay.model.MobileSegment
|
|
6
5
|
import com.datadog.reactnative.sessionreplay.utils.DrawableUtils
|
|
7
6
|
import com.datadog.reactnative.sessionreplay.utils.formatAsRgba
|
|
@@ -19,10 +18,7 @@ internal class ReactViewBackgroundDrawableUtils() : DrawableUtils() {
|
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
val borderProps = resolveBorder(drawable, pixelDensity)
|
|
22
|
-
val cornerRadius = drawable
|
|
23
|
-
.fullBorderRadius
|
|
24
|
-
.toLong()
|
|
25
|
-
.densityNormalized(pixelDensity)
|
|
21
|
+
val cornerRadius = (drawable.fullBorderRadius / pixelDensity).toLong()
|
|
26
22
|
|
|
27
23
|
val backgroundColor = getBackgroundColor(drawable)
|
|
28
24
|
val colorHexString = if (backgroundColor != null) {
|
|
@@ -63,8 +59,7 @@ internal class ReactViewBackgroundDrawableUtils() : DrawableUtils() {
|
|
|
63
59
|
backgroundDrawable: ReactViewBackgroundDrawable,
|
|
64
60
|
pixelDensity: Float
|
|
65
61
|
): MobileSegment.ShapeBorder {
|
|
66
|
-
val borderWidth =
|
|
67
|
-
backgroundDrawable.fullBorderWidth.toLong().densityNormalized(pixelDensity)
|
|
62
|
+
val borderWidth = (backgroundDrawable.fullBorderWidth / pixelDensity).toLong()
|
|
68
63
|
val borderColor = formatAsRgba(backgroundDrawable.getBorderColor(Spacing.ALL))
|
|
69
64
|
|
|
70
65
|
return MobileSegment.ShapeBorder(
|
|
@@ -11,6 +11,7 @@ import com.datadog.reactnative.sessionreplay.mappers.ReactEditTextMapper
|
|
|
11
11
|
import com.datadog.reactnative.sessionreplay.mappers.ReactNativeImageViewMapper
|
|
12
12
|
import com.datadog.reactnative.sessionreplay.mappers.ReactTextMapper
|
|
13
13
|
import com.datadog.reactnative.sessionreplay.mappers.ReactViewGroupMapper
|
|
14
|
+
import com.datadog.reactnative.sessionreplay.utils.text.TextViewUtils
|
|
14
15
|
import com.facebook.react.bridge.NativeModule
|
|
15
16
|
import com.facebook.react.bridge.ReactContext
|
|
16
17
|
import com.facebook.react.uimanager.UIManagerModule
|
|
@@ -51,10 +52,8 @@ internal class ReactNativeSessionReplayExtensionSupportTest {
|
|
|
51
52
|
whenever(mockReactContext.getNativeModule(any<Class<NativeModule>>()))
|
|
52
53
|
.doReturn(mockUiManagerModule)
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
reactContext = mockReactContext
|
|
57
|
-
)
|
|
55
|
+
val textViewUtils = TextViewUtils.create(mockReactContext, mockLogger)
|
|
56
|
+
testedExtensionSupport = ReactNativeSessionReplayExtensionSupport(textViewUtils)
|
|
58
57
|
}
|
|
59
58
|
|
|
60
59
|
@Test
|
|
@@ -77,17 +76,4 @@ internal class ReactNativeSessionReplayExtensionSupportTest {
|
|
|
77
76
|
assertThat(customViewMappers[3].getUnsafeMapper())
|
|
78
77
|
.isInstanceOf(ReactEditTextMapper::class.java)
|
|
79
78
|
}
|
|
80
|
-
|
|
81
|
-
@Test
|
|
82
|
-
fun `M return null W getUiManagerModule() { cannot get uiManagerModule }`() {
|
|
83
|
-
// Given
|
|
84
|
-
whenever(mockReactContext.getNativeModule(any<Class<NativeModule>>()))
|
|
85
|
-
.thenThrow(IllegalStateException())
|
|
86
|
-
|
|
87
|
-
// When
|
|
88
|
-
val uiManagerModule = testedExtensionSupport.getUiManagerModule()
|
|
89
|
-
|
|
90
|
-
// Then
|
|
91
|
-
assertThat(uiManagerModule).isNull()
|
|
92
|
-
}
|
|
93
79
|
}
|