@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
|
@@ -17,27 +17,11 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
|
17
17
|
internal var identifier = UUID()
|
|
18
18
|
|
|
19
19
|
internal let uiManager: RCTUIManager
|
|
20
|
+
internal let fabricWrapper: RCTFabricWrapper
|
|
20
21
|
|
|
21
|
-
internal init(uiManager: RCTUIManager) {
|
|
22
|
+
internal init(uiManager: RCTUIManager, fabricWrapper: RCTFabricWrapper) {
|
|
22
23
|
self.uiManager = uiManager
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
internal func extractTextFromSubViews(
|
|
26
|
-
subviews: [RCTShadowView]?
|
|
27
|
-
) -> String? {
|
|
28
|
-
if let subviews = subviews {
|
|
29
|
-
return subviews.compactMap { subview in
|
|
30
|
-
if let sub = subview as? RCTRawTextShadowView {
|
|
31
|
-
return sub.text
|
|
32
|
-
}
|
|
33
|
-
if let sub = subview as? RCTVirtualTextShadowView {
|
|
34
|
-
// We recursively get all subviews for nested Text components
|
|
35
|
-
return extractTextFromSubViews(subviews: sub.reactSubviews())
|
|
36
|
-
}
|
|
37
|
-
return nil
|
|
38
|
-
}.joined()
|
|
39
|
-
}
|
|
40
|
-
return nil
|
|
24
|
+
self.fabricWrapper = fabricWrapper
|
|
41
25
|
}
|
|
42
26
|
|
|
43
27
|
public func semantics(
|
|
@@ -45,6 +29,48 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
|
45
29
|
with attributes: SessionReplayViewAttributes,
|
|
46
30
|
in context: SessionReplayViewTreeRecordingContext
|
|
47
31
|
) -> SessionReplayNodeSemantics? {
|
|
32
|
+
guard
|
|
33
|
+
let textProperties = fabricWrapper.tryToExtractTextProperties(from: view) ?? tryToExtractTextProperties(view: view)
|
|
34
|
+
else {
|
|
35
|
+
return view is RCTTextView ? SessionReplayInvisibleElement.constant : nil
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let builder = RCTTextViewWireframesBuilder(
|
|
39
|
+
wireframeID: context.ids.nodeID(view: view, nodeRecorder: self),
|
|
40
|
+
attributes: attributes,
|
|
41
|
+
text: textProperties.text,
|
|
42
|
+
textAlignment: textProperties.alignment,
|
|
43
|
+
textColor: textProperties.foregroundColor,
|
|
44
|
+
textObfuscator: textObfuscator(context),
|
|
45
|
+
fontSize: textProperties.fontSize,
|
|
46
|
+
contentRect: textProperties.contentRect
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return SessionReplaySpecificElement(subtreeStrategy: .ignore, nodes: [
|
|
50
|
+
SessionReplayNode(viewAttributes: attributes, wireframesBuilder: builder)
|
|
51
|
+
])
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
internal func tryToExtractTextFromSubViews(
|
|
55
|
+
subviews: [RCTShadowView]?
|
|
56
|
+
) -> String? {
|
|
57
|
+
guard let subviews = subviews else {
|
|
58
|
+
return nil
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return subviews.compactMap { subview in
|
|
62
|
+
if let sub = subview as? RCTRawTextShadowView {
|
|
63
|
+
return sub.text
|
|
64
|
+
}
|
|
65
|
+
if let sub = subview as? RCTVirtualTextShadowView {
|
|
66
|
+
// We recursively get all subviews for nested Text components
|
|
67
|
+
return tryToExtractTextFromSubViews(subviews: sub.reactSubviews())
|
|
68
|
+
}
|
|
69
|
+
return nil
|
|
70
|
+
}.joined()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private func tryToExtractTextProperties(view: UIView) -> RCTTextPropertiesWrapper? {
|
|
48
74
|
guard let textView = view as? RCTTextView else {
|
|
49
75
|
return nil
|
|
50
76
|
}
|
|
@@ -56,41 +82,35 @@ internal class RCTTextViewRecorder: SessionReplayNodeRecorder {
|
|
|
56
82
|
shadowView = uiManager.shadowView(forReactTag: tag) as? RCTTextShadowView
|
|
57
83
|
}
|
|
58
84
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
subviews: shadow.reactSubviews()
|
|
63
|
-
)
|
|
85
|
+
guard let shadow = shadowView else {
|
|
86
|
+
return nil
|
|
87
|
+
}
|
|
64
88
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
textColor: shadow.textAttributes.foregroundColor?.cgColor,
|
|
71
|
-
textObfuscator: textObfuscator(context),
|
|
72
|
-
fontSize: shadow.textAttributes.fontSize,
|
|
73
|
-
contentRect: shadow.contentFrame
|
|
74
|
-
)
|
|
75
|
-
let node = SessionReplayNode(viewAttributes: attributes, wireframesBuilder: builder)
|
|
76
|
-
return SessionReplaySpecificElement(subtreeStrategy: .ignore, nodes: [node])
|
|
89
|
+
let textProperties = RCTTextPropertiesWrapper()
|
|
90
|
+
|
|
91
|
+
// TODO: RUM-2173 check performance is ok
|
|
92
|
+
if let text = tryToExtractTextFromSubViews(subviews: shadow.reactSubviews()) {
|
|
93
|
+
textProperties.text = text
|
|
77
94
|
}
|
|
78
|
-
return SessionReplayInvisibleElement.constant
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
95
|
|
|
82
|
-
|
|
83
|
-
|
|
96
|
+
if let foregroundColor = shadow.textAttributes.foregroundColor {
|
|
97
|
+
textProperties.foregroundColor = foregroundColor
|
|
98
|
+
}
|
|
84
99
|
|
|
85
|
-
|
|
86
|
-
|
|
100
|
+
textProperties.alignment = shadow.textAttributes.alignment
|
|
101
|
+
textProperties.fontSize = shadow.textAttributes.fontSize
|
|
102
|
+
textProperties.contentRect = shadow.contentFrame
|
|
103
|
+
|
|
104
|
+
return textProperties
|
|
105
|
+
}
|
|
106
|
+
}
|
|
87
107
|
|
|
88
108
|
internal struct RCTTextViewWireframesBuilder: SessionReplayNodeWireframesBuilder {
|
|
89
109
|
let wireframeID: WireframeID
|
|
90
110
|
let attributes: SessionReplayViewAttributes
|
|
91
|
-
let text: String
|
|
111
|
+
let text: String
|
|
92
112
|
var textAlignment: NSTextAlignment
|
|
93
|
-
let textColor:
|
|
113
|
+
let textColor: UIColor
|
|
94
114
|
let textObfuscator: SessionReplayTextObfuscating
|
|
95
115
|
let fontSize: CGFloat
|
|
96
116
|
let contentRect: CGRect
|
|
@@ -140,12 +160,12 @@ internal struct RCTTextViewWireframesBuilder: SessionReplayNodeWireframesBuilder
|
|
|
140
160
|
id: wireframeID,
|
|
141
161
|
frame: relativeIntersectedRect,
|
|
142
162
|
clip: attributes.clip,
|
|
143
|
-
text: textObfuscator.mask(text: text
|
|
163
|
+
text: textObfuscator.mask(text: text),
|
|
144
164
|
textFrame: textFrame,
|
|
145
|
-
// Text alignment is top for all RCTTextView components.
|
|
165
|
+
// Text alignment is top for all RCTTextView and RCTParagraphComponentView components.
|
|
146
166
|
textAlignment: .init(systemTextAlignment: textAlignment, vertical: .top),
|
|
147
|
-
textColor: textColor
|
|
148
|
-
fontOverride: SessionReplayWireframesBuilder.FontOverride(size: fontSize.isNaN ?
|
|
167
|
+
textColor: textColor.cgColor,
|
|
168
|
+
fontOverride: SessionReplayWireframesBuilder.FontOverride(size: fontSize.isNaN ? RCTTextPropertiesDefaultFontSize : fontSize),
|
|
149
169
|
borderColor: attributes.layerBorderColor,
|
|
150
170
|
borderWidth: attributes.layerBorderWidth,
|
|
151
171
|
backgroundColor: attributes.backgroundColor,
|
|
@@ -36,7 +36,7 @@ let TextAndInputPrivacyLevel = exports.TextAndInputPrivacyLevel = /*#__PURE__*/f
|
|
|
36
36
|
* The Session Replay configuration object.
|
|
37
37
|
*/
|
|
38
38
|
const DEFAULTS = {
|
|
39
|
-
replaySampleRate:
|
|
39
|
+
replaySampleRate: 100,
|
|
40
40
|
defaultPrivacyLevel: SessionReplayPrivacy.MASK,
|
|
41
41
|
customEndpoint: '',
|
|
42
42
|
imagePrivacyLevel: ImagePrivacyLevel.MASK_ALL,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["SessionReplayPrivacy","exports","ImagePrivacyLevel","TouchPrivacyLevel","TextAndInputPrivacyLevel","DEFAULTS","replaySampleRate","defaultPrivacyLevel","MASK","customEndpoint","imagePrivacyLevel","MASK_ALL","touchPrivacyLevel","HIDE","textAndInputPrivacyLevel","startRecordingImmediately","SessionReplayWrapper","nativeSessionReplay","require","default","buildConfiguration","configuration","baseConfig","undefined","privacyConfig","MASK_USER_INPUT","MASK_NONE","MASK_ALL_INPUTS","ALLOW","SHOW","MASK_SENSITIVE_INPUTS","enable","startRecording","stopRecording","SessionReplay"],"sourceRoot":"../../src","sources":["SessionReplay.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AAJA,IAQYA,oBAAoB,GAAAC,OAAA,CAAAD,oBAAA,0BAApBA,oBAAoB;EAApBA,oBAAoB;EAApBA,oBAAoB;EAApBA,oBAAoB;EAAA,OAApBA,oBAAoB;AAAA;AAAA,IAMpBE,iBAAiB,GAAAD,OAAA,CAAAC,iBAAA,0BAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAA,OAAjBA,iBAAiB;AAAA;AAAA,IAiBjBC,iBAAiB,GAAAF,OAAA,CAAAE,iBAAA,0BAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAA,OAAjBA,iBAAiB;AAAA;AAAA,IAWjBC,wBAAwB,GAAAH,OAAA,CAAAG,wBAAA,0BAAxBA,wBAAwB;EAAxBA,wBAAwB;EAAxBA,wBAAwB;EAAxBA,wBAAwB;EAAA,OAAxBA,wBAAwB;AAAA;AAepC;AACA;AACA;AAgEA,MAAMC,QAEL,GAAG;EACAC,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"names":["SessionReplayPrivacy","exports","ImagePrivacyLevel","TouchPrivacyLevel","TextAndInputPrivacyLevel","DEFAULTS","replaySampleRate","defaultPrivacyLevel","MASK","customEndpoint","imagePrivacyLevel","MASK_ALL","touchPrivacyLevel","HIDE","textAndInputPrivacyLevel","startRecordingImmediately","SessionReplayWrapper","nativeSessionReplay","require","default","buildConfiguration","configuration","baseConfig","undefined","privacyConfig","MASK_USER_INPUT","MASK_NONE","MASK_ALL_INPUTS","ALLOW","SHOW","MASK_SENSITIVE_INPUTS","enable","startRecording","stopRecording","SessionReplay"],"sourceRoot":"../../src","sources":["SessionReplay.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -33,7 +33,7 @@ export let TextAndInputPrivacyLevel = /*#__PURE__*/function (TextAndInputPrivacy
|
|
|
33
33
|
*/
|
|
34
34
|
|
|
35
35
|
const DEFAULTS = {
|
|
36
|
-
replaySampleRate:
|
|
36
|
+
replaySampleRate: 100,
|
|
37
37
|
defaultPrivacyLevel: SessionReplayPrivacy.MASK,
|
|
38
38
|
customEndpoint: '',
|
|
39
39
|
imagePrivacyLevel: ImagePrivacyLevel.MASK_ALL,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["SessionReplayPrivacy","ImagePrivacyLevel","TouchPrivacyLevel","TextAndInputPrivacyLevel","DEFAULTS","replaySampleRate","defaultPrivacyLevel","MASK","customEndpoint","imagePrivacyLevel","MASK_ALL","touchPrivacyLevel","HIDE","textAndInputPrivacyLevel","startRecordingImmediately","SessionReplayWrapper","nativeSessionReplay","require","default","buildConfiguration","configuration","baseConfig","undefined","privacyConfig","MASK_USER_INPUT","MASK_NONE","MASK_ALL_INPUTS","ALLOW","SHOW","MASK_SENSITIVE_INPUTS","enable","startRecording","stopRecording","SessionReplay"],"sourceRoot":"../../src","sources":["SessionReplay.ts"],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAIA,WAAYA,oBAAoB,0BAApBA,oBAAoB;EAApBA,oBAAoB;EAApBA,oBAAoB;EAApBA,oBAAoB;EAAA,OAApBA,oBAAoB;AAAA;AAMhC,WAAYC,iBAAiB,0BAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAA,OAAjBA,iBAAiB;AAAA;AAiB7B,WAAYC,iBAAiB,0BAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAjBA,iBAAiB;EAAA,OAAjBA,iBAAiB;AAAA;AAW7B,WAAYC,wBAAwB,0BAAxBA,wBAAwB;EAAxBA,wBAAwB;EAAxBA,wBAAwB;EAAxBA,wBAAwB;EAAA,OAAxBA,wBAAwB;AAAA;;AAepC;AACA;AACA;;AAgEA,MAAMC,QAEL,GAAG;EACAC,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"names":["SessionReplayPrivacy","ImagePrivacyLevel","TouchPrivacyLevel","TextAndInputPrivacyLevel","DEFAULTS","replaySampleRate","defaultPrivacyLevel","MASK","customEndpoint","imagePrivacyLevel","MASK_ALL","touchPrivacyLevel","HIDE","textAndInputPrivacyLevel","startRecordingImmediately","SessionReplayWrapper","nativeSessionReplay","require","default","buildConfiguration","configuration","baseConfig","undefined","privacyConfig","MASK_USER_INPUT","MASK_NONE","MASK_ALL_INPUTS","ALLOW","SHOW","MASK_SENSITIVE_INPUTS","enable","startRecording","stopRecording","SessionReplay"],"sourceRoot":"../../src","sources":["SessionReplay.ts"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datadog/mobile-react-native-session-replay",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "A client-side React Native module to enable session replay with Datadog",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"datadog",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"files": [
|
|
20
20
|
"src/**",
|
|
21
21
|
"lib/**",
|
|
22
|
+
"scripts/**",
|
|
22
23
|
"android/build.gradle",
|
|
23
24
|
"android/detekt.yml",
|
|
24
25
|
"android/gradle.properties",
|
|
@@ -40,7 +41,8 @@
|
|
|
40
41
|
"scripts": {
|
|
41
42
|
"test": "jest",
|
|
42
43
|
"lint": "eslint .",
|
|
43
|
-
"prepare": "rm -rf lib && yarn bob build"
|
|
44
|
+
"prepare": "rm -rf lib && yarn bob build",
|
|
45
|
+
"postinstall": "node scripts/set-ios-rn-version.js"
|
|
44
46
|
},
|
|
45
47
|
"peerDependencies": {
|
|
46
48
|
"react": ">=16.13.1",
|
|
@@ -87,5 +89,6 @@
|
|
|
87
89
|
"android": {
|
|
88
90
|
"javaPackageName": "com.datadog.reactnative.sessionreplay"
|
|
89
91
|
}
|
|
90
|
-
}
|
|
92
|
+
},
|
|
93
|
+
"gitHead": "d6ff835a3572d9897b0c1c8ed47fbbba9bc2f4df"
|
|
91
94
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
function getReactNativeVersion() {
|
|
11
|
+
try {
|
|
12
|
+
// eslint-disable-next-line global-require
|
|
13
|
+
return require('react-native/package.json').version;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
throw new Error(
|
|
16
|
+
'Failed to find React Native. Ensure it is installed in your project.'
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const rnVersion = getReactNativeVersion();
|
|
22
|
+
|
|
23
|
+
const outputDir = path.resolve(__dirname, '../ios/Sources');
|
|
24
|
+
const outputFile = path.join(outputDir, 'RCTVersion.h');
|
|
25
|
+
|
|
26
|
+
if (!fs.existsSync(outputDir)) {
|
|
27
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const [major, minor, patch] = rnVersion.split('.').map(Number);
|
|
31
|
+
|
|
32
|
+
const headerContent = `#ifndef RCTVersion_h
|
|
33
|
+
#define RCTVersion_h
|
|
34
|
+
|
|
35
|
+
#define RCT_VERSION_MAJOR ${major || 0}
|
|
36
|
+
#define RCT_VERSION_MINOR ${minor || 0}
|
|
37
|
+
#define RCT_VERSION_PATCH ${patch || 0}
|
|
38
|
+
|
|
39
|
+
#endif /* RCTVersion_h */
|
|
40
|
+
`;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
fs.writeFileSync(outputFile, headerContent, 'utf8');
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(`Failed to write RCTVersion.h: ${error.message}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
package/src/SessionReplay.ts
CHANGED
|
@@ -124,7 +124,7 @@ type InternalSessionReplayConfiguration = InternalBaseSessionReplayConfiguration
|
|
|
124
124
|
const DEFAULTS: InternalSessionReplayConfiguration & {
|
|
125
125
|
defaultPrivacyLevel: SessionReplayPrivacy;
|
|
126
126
|
} = {
|
|
127
|
-
replaySampleRate:
|
|
127
|
+
replaySampleRate: 100,
|
|
128
128
|
defaultPrivacyLevel: SessionReplayPrivacy.MASK,
|
|
129
129
|
customEndpoint: '',
|
|
130
130
|
imagePrivacyLevel: ImagePrivacyLevel.MASK_ALL,
|
package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/NoopTextPropertiesResolver.kt
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
* * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
4
|
-
* * This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
5
|
-
* * Copyright 2016-Present Datadog, Inc.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
package com.datadog.reactnative.sessionreplay
|
|
10
|
-
|
|
11
|
-
import android.widget.TextView
|
|
12
|
-
import com.datadog.android.sessionreplay.model.MobileSegment
|
|
13
|
-
|
|
14
|
-
internal class NoopTextPropertiesResolver: TextPropertiesResolver {
|
|
15
|
-
override fun addReactNativeProperties(
|
|
16
|
-
originalWireframe: MobileSegment.Wireframe.TextWireframe,
|
|
17
|
-
view: TextView,
|
|
18
|
-
pixelDensity: Float
|
|
19
|
-
): MobileSegment.Wireframe.TextWireframe {
|
|
20
|
-
return originalWireframe
|
|
21
|
-
}
|
|
22
|
-
}
|
package/android/src/main/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtils.kt
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
*
|
|
3
|
-
* * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0.
|
|
4
|
-
* * This product includes software developed at Datadog (https://www.datadoghq.com/).
|
|
5
|
-
* * Copyright 2016-Present Datadog, Inc.
|
|
6
|
-
*
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
package com.datadog.reactnative.sessionreplay.utils
|
|
10
|
-
|
|
11
|
-
import android.widget.TextView
|
|
12
|
-
import com.datadog.android.sessionreplay.model.MobileSegment
|
|
13
|
-
import com.datadog.android.sessionreplay.recorder.MappingContext
|
|
14
|
-
import com.datadog.reactnative.sessionreplay.TextPropertiesResolver
|
|
15
|
-
|
|
16
|
-
internal class TextViewUtils {
|
|
17
|
-
internal fun mapTextViewToWireframes(
|
|
18
|
-
wireframes: List<MobileSegment.Wireframe>,
|
|
19
|
-
view: TextView,
|
|
20
|
-
mappingContext: MappingContext,
|
|
21
|
-
reactTextPropertiesResolver: TextPropertiesResolver
|
|
22
|
-
): List<MobileSegment.Wireframe> {
|
|
23
|
-
val result = mutableListOf<MobileSegment.Wireframe>()
|
|
24
|
-
val pixelDensity = mappingContext.systemInformation.screenDensity
|
|
25
|
-
|
|
26
|
-
for (originalWireframe in wireframes) {
|
|
27
|
-
if (originalWireframe !is MobileSegment.Wireframe.TextWireframe) {
|
|
28
|
-
result.add(originalWireframe)
|
|
29
|
-
} else {
|
|
30
|
-
result.add(reactTextPropertiesResolver.addReactNativeProperties(
|
|
31
|
-
originalWireframe = originalWireframe,
|
|
32
|
-
view = view,
|
|
33
|
-
pixelDensity = pixelDensity,
|
|
34
|
-
))
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return result
|
|
39
|
-
}
|
|
40
|
-
}
|
package/android/src/test/kotlin/com/datadog/reactnative/sessionreplay/utils/TextViewUtilsTest.kt
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
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.utils
|
|
8
|
-
|
|
9
|
-
import android.content.res.Resources
|
|
10
|
-
import android.graphics.Typeface
|
|
11
|
-
import android.util.DisplayMetrics
|
|
12
|
-
import android.widget.TextView
|
|
13
|
-
import com.datadog.android.sessionreplay.model.MobileSegment
|
|
14
|
-
import com.datadog.android.sessionreplay.recorder.MappingContext
|
|
15
|
-
import com.datadog.android.sessionreplay.recorder.SystemInformation
|
|
16
|
-
import com.datadog.reactnative.sessionreplay.ReactTextPropertiesResolver
|
|
17
|
-
import fr.xgouchet.elmyr.Forge
|
|
18
|
-
import fr.xgouchet.elmyr.junit5.ForgeExtension
|
|
19
|
-
import org.assertj.core.api.Assertions.assertThat
|
|
20
|
-
import org.junit.jupiter.api.BeforeEach
|
|
21
|
-
import org.junit.jupiter.api.Test
|
|
22
|
-
import org.junit.jupiter.api.extension.ExtendWith
|
|
23
|
-
import org.junit.jupiter.api.extension.Extensions
|
|
24
|
-
import org.mockito.Mock
|
|
25
|
-
import org.mockito.junit.jupiter.MockitoExtension
|
|
26
|
-
import org.mockito.junit.jupiter.MockitoSettings
|
|
27
|
-
import org.mockito.kotlin.eq
|
|
28
|
-
import org.mockito.kotlin.whenever
|
|
29
|
-
import org.mockito.quality.Strictness
|
|
30
|
-
|
|
31
|
-
@Extensions(
|
|
32
|
-
ExtendWith(MockitoExtension::class),
|
|
33
|
-
ExtendWith(ForgeExtension::class)
|
|
34
|
-
)
|
|
35
|
-
@MockitoSettings(strictness = Strictness.LENIENT)
|
|
36
|
-
internal class TextViewUtilsTest {
|
|
37
|
-
private lateinit var testedUtils: TextViewUtils
|
|
38
|
-
|
|
39
|
-
@Mock
|
|
40
|
-
private lateinit var mockReactTextPropertiesResolver: ReactTextPropertiesResolver
|
|
41
|
-
|
|
42
|
-
@Mock
|
|
43
|
-
private lateinit var mockMappingContext: MappingContext
|
|
44
|
-
|
|
45
|
-
@Mock
|
|
46
|
-
private lateinit var mockTextView: TextView
|
|
47
|
-
|
|
48
|
-
@Mock
|
|
49
|
-
private lateinit var mockSystemInformation: SystemInformation
|
|
50
|
-
|
|
51
|
-
@Mock
|
|
52
|
-
private lateinit var mockResources: Resources
|
|
53
|
-
|
|
54
|
-
@Mock
|
|
55
|
-
private lateinit var mockDisplayMetrics: DisplayMetrics
|
|
56
|
-
|
|
57
|
-
@BeforeEach
|
|
58
|
-
fun `set up`(forge: Forge) {
|
|
59
|
-
whenever(mockResources.displayMetrics).thenReturn(mockDisplayMetrics)
|
|
60
|
-
whenever(mockTextView.resources).thenReturn(mockResources)
|
|
61
|
-
whenever(mockSystemInformation.screenDensity).thenReturn(0f)
|
|
62
|
-
whenever(mockMappingContext.systemInformation).thenReturn(mockSystemInformation)
|
|
63
|
-
whenever(mockTextView.text).thenReturn(forge.aString())
|
|
64
|
-
whenever(mockTextView.typeface).thenReturn(Typeface.SANS_SERIF)
|
|
65
|
-
|
|
66
|
-
testedUtils = TextViewUtils()
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
@Test
|
|
70
|
-
fun `M return wireframe W map() { even if not TextWireframeType }`(
|
|
71
|
-
@Mock mockImageWireframe: MobileSegment.Wireframe.ImageWireframe
|
|
72
|
-
) {
|
|
73
|
-
// When
|
|
74
|
-
val result = testedUtils.mapTextViewToWireframes(
|
|
75
|
-
wireframes = listOf(mockImageWireframe),
|
|
76
|
-
view = mockTextView,
|
|
77
|
-
mappingContext = mockMappingContext,
|
|
78
|
-
reactTextPropertiesResolver = mockReactTextPropertiesResolver
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
// Then
|
|
82
|
-
assertThat(result).contains(mockImageWireframe)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
@Test
|
|
86
|
-
fun `M return textWireframe W map()`(
|
|
87
|
-
@Mock mockTextWireframe: MobileSegment.Wireframe.TextWireframe
|
|
88
|
-
) {
|
|
89
|
-
// Given
|
|
90
|
-
whenever(
|
|
91
|
-
mockReactTextPropertiesResolver.addReactNativeProperties(
|
|
92
|
-
originalWireframe = eq(mockTextWireframe),
|
|
93
|
-
view = eq(mockTextView),
|
|
94
|
-
pixelDensity = eq(0f)
|
|
95
|
-
)
|
|
96
|
-
).thenReturn(mockTextWireframe)
|
|
97
|
-
|
|
98
|
-
// When
|
|
99
|
-
val result = testedUtils.mapTextViewToWireframes(
|
|
100
|
-
wireframes = listOf(mockTextWireframe),
|
|
101
|
-
view = mockTextView,
|
|
102
|
-
mappingContext = mockMappingContext,
|
|
103
|
-
reactTextPropertiesResolver = mockReactTextPropertiesResolver
|
|
104
|
-
)[0] as MobileSegment.Wireframe.TextWireframe
|
|
105
|
-
|
|
106
|
-
// Then
|
|
107
|
-
assertThat(result).isEqualTo(mockTextWireframe)
|
|
108
|
-
}
|
|
109
|
-
}
|