@repliqo/sdk-react-native 0.3.3 → 0.3.4
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.
|
@@ -4,8 +4,8 @@ import { ScrollView, type ScrollViewProps } from 'react-native';
|
|
|
4
4
|
* Drop-in replacement for React Native's ScrollView that:
|
|
5
5
|
*
|
|
6
6
|
* 1. Reports scroll offset for accurate heatmap touch coords
|
|
7
|
-
* 2. Captures viewport tiles on scroll stops
|
|
8
|
-
* screen building — the backend composites
|
|
9
|
-
* full-content image over time
|
|
7
|
+
* 2. Captures viewport tiles on scroll stops AND during continuous
|
|
8
|
+
* scroll for collaborative screen building — the backend composites
|
|
9
|
+
* these into a full-content image over time
|
|
10
10
|
*/
|
|
11
11
|
export declare const RepliqoScrollView: React.ForwardRefExoticComponent<ScrollViewProps & React.RefAttributes<ScrollView>>;
|
|
@@ -40,41 +40,54 @@ const client_1 = require("../core/client");
|
|
|
40
40
|
/** Minimum scroll delta (px) to trigger a new tile capture. */
|
|
41
41
|
const MIN_DELTA_PX = 20;
|
|
42
42
|
/** Debounce: wait this long after scroll stops before capturing. */
|
|
43
|
-
const DEBOUNCE_MS =
|
|
43
|
+
const DEBOUNCE_MS = 250;
|
|
44
44
|
/** Throttle: minimum time between tile captures. */
|
|
45
|
-
const THROTTLE_MS =
|
|
45
|
+
const THROTTLE_MS = 400;
|
|
46
|
+
/**
|
|
47
|
+
* During continuous scroll, force a capture every this many ms.
|
|
48
|
+
* Ensures tiles are captured even during fast, uninterrupted scrolls
|
|
49
|
+
* where the user never pauses long enough for the debounce to fire.
|
|
50
|
+
*/
|
|
51
|
+
const SCROLL_INTERVAL_MS = 1200;
|
|
46
52
|
/**
|
|
47
53
|
* Drop-in replacement for React Native's ScrollView that:
|
|
48
54
|
*
|
|
49
55
|
* 1. Reports scroll offset for accurate heatmap touch coords
|
|
50
|
-
* 2. Captures viewport tiles on scroll stops
|
|
51
|
-
* screen building — the backend composites
|
|
52
|
-
* full-content image over time
|
|
56
|
+
* 2. Captures viewport tiles on scroll stops AND during continuous
|
|
57
|
+
* scroll for collaborative screen building — the backend composites
|
|
58
|
+
* these into a full-content image over time
|
|
53
59
|
*/
|
|
54
|
-
exports.RepliqoScrollView = react_1.default.forwardRef(({ onScroll, onMomentumScrollEnd, onScrollEndDrag, onLayout, ...props }, ref) => {
|
|
60
|
+
exports.RepliqoScrollView = react_1.default.forwardRef(({ onScroll, onMomentumScrollEnd, onScrollEndDrag, onLayout, onContentSizeChange, ...props }, ref) => {
|
|
55
61
|
const debounceTimer = (0, react_1.useRef)(null);
|
|
62
|
+
const scrollIntervalTimer = (0, react_1.useRef)(null);
|
|
56
63
|
const lastCaptureTime = (0, react_1.useRef)(0);
|
|
57
64
|
const lastCaptureY = (0, react_1.useRef)(-999);
|
|
58
65
|
const initialCaptured = (0, react_1.useRef)(false);
|
|
66
|
+
const realContentHeight = (0, react_1.useRef)(0);
|
|
59
67
|
const scrollState = (0, react_1.useRef)(null);
|
|
60
|
-
// Cleanup
|
|
68
|
+
// Cleanup timers on unmount
|
|
61
69
|
(0, react_1.useEffect)(() => {
|
|
62
70
|
return () => {
|
|
63
71
|
if (debounceTimer.current)
|
|
64
72
|
clearTimeout(debounceTimer.current);
|
|
73
|
+
if (scrollIntervalTimer.current)
|
|
74
|
+
clearInterval(scrollIntervalTimer.current);
|
|
65
75
|
};
|
|
66
76
|
}, []);
|
|
67
77
|
/**
|
|
68
78
|
* Core tile capture logic. Reads from refs (stable across renders).
|
|
69
79
|
* Checks throttle + delta before capturing.
|
|
80
|
+
*
|
|
81
|
+
* @param force Skip throttle check (used for interval captures)
|
|
70
82
|
*/
|
|
71
|
-
const doCapture = () => {
|
|
83
|
+
const doCapture = (force = false) => {
|
|
72
84
|
const state = scrollState.current;
|
|
73
85
|
if (!state || state.viewportHeight <= 0)
|
|
74
86
|
return;
|
|
75
87
|
const now = Date.now();
|
|
76
|
-
if (now - lastCaptureTime.current < THROTTLE_MS)
|
|
88
|
+
if (!force && now - lastCaptureTime.current < THROTTLE_MS)
|
|
77
89
|
return;
|
|
90
|
+
// Always check delta — no point re-capturing the same position
|
|
78
91
|
if (Math.abs(state.offsetY - lastCaptureY.current) < MIN_DELTA_PX &&
|
|
79
92
|
initialCaptured.current)
|
|
80
93
|
return;
|
|
@@ -86,6 +99,21 @@ exports.RepliqoScrollView = react_1.default.forwardRef(({ onScroll, onMomentumSc
|
|
|
86
99
|
}
|
|
87
100
|
catch { }
|
|
88
101
|
};
|
|
102
|
+
/** Start the interval timer for continuous scroll captures. */
|
|
103
|
+
const startScrollInterval = () => {
|
|
104
|
+
if (scrollIntervalTimer.current !== null)
|
|
105
|
+
return;
|
|
106
|
+
scrollIntervalTimer.current = setInterval(() => {
|
|
107
|
+
doCapture(true); // force=true skips throttle
|
|
108
|
+
}, SCROLL_INTERVAL_MS);
|
|
109
|
+
};
|
|
110
|
+
/** Stop the interval timer. */
|
|
111
|
+
const stopScrollInterval = () => {
|
|
112
|
+
if (scrollIntervalTimer.current !== null) {
|
|
113
|
+
clearInterval(scrollIntervalTimer.current);
|
|
114
|
+
scrollIntervalTimer.current = null;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
89
117
|
const handleScroll = (0, react_1.useCallback)((event) => {
|
|
90
118
|
const { contentOffset, layoutMeasurement, contentSize } = event.nativeEvent;
|
|
91
119
|
// Report scroll offset for touch coords
|
|
@@ -93,25 +121,31 @@ exports.RepliqoScrollView = react_1.default.forwardRef(({ onScroll, onMomentumSc
|
|
|
93
121
|
client_1.AppAnalytics.getInstance().setScrollOffset(contentOffset.y);
|
|
94
122
|
}
|
|
95
123
|
catch { }
|
|
96
|
-
// Update scroll state
|
|
124
|
+
// Update scroll state — use realContentHeight if available
|
|
125
|
+
const bestContentHeight = realContentHeight.current > 0
|
|
126
|
+
? realContentHeight.current
|
|
127
|
+
: contentSize.height;
|
|
97
128
|
scrollState.current = {
|
|
98
129
|
offsetY: contentOffset.y,
|
|
99
130
|
viewportHeight: layoutMeasurement.height,
|
|
100
|
-
contentHeight:
|
|
131
|
+
contentHeight: bestContentHeight,
|
|
101
132
|
};
|
|
102
133
|
// Debounce: capture after scroll stops
|
|
103
134
|
if (debounceTimer.current)
|
|
104
135
|
clearTimeout(debounceTimer.current);
|
|
105
|
-
debounceTimer.current = setTimeout(doCapture, DEBOUNCE_MS);
|
|
106
|
-
//
|
|
136
|
+
debounceTimer.current = setTimeout(() => doCapture(), DEBOUNCE_MS);
|
|
137
|
+
// Start interval for continuous scroll captures
|
|
138
|
+
startScrollInterval();
|
|
139
|
+
// Capture initial tile (Y~0) on first scroll event with real dims
|
|
107
140
|
if (!initialCaptured.current && contentOffset.y < 10) {
|
|
108
|
-
setTimeout(doCapture, 200);
|
|
141
|
+
setTimeout(() => doCapture(), 200);
|
|
109
142
|
}
|
|
110
143
|
onScroll?.(event);
|
|
111
144
|
}, [onScroll]);
|
|
112
145
|
const handleScrollEndDrag = (0, react_1.useCallback)((event) => {
|
|
113
146
|
// User lifted finger — capture immediately
|
|
114
|
-
|
|
147
|
+
stopScrollInterval();
|
|
148
|
+
doCapture(true);
|
|
115
149
|
onScrollEndDrag?.(event);
|
|
116
150
|
}, [onScrollEndDrag]);
|
|
117
151
|
const handleMomentumEnd = (0, react_1.useCallback)((event) => {
|
|
@@ -119,7 +153,8 @@ exports.RepliqoScrollView = react_1.default.forwardRef(({ onScroll, onMomentumSc
|
|
|
119
153
|
clearTimeout(debounceTimer.current);
|
|
120
154
|
debounceTimer.current = null;
|
|
121
155
|
}
|
|
122
|
-
|
|
156
|
+
stopScrollInterval();
|
|
157
|
+
doCapture(true);
|
|
123
158
|
onMomentumScrollEnd?.(event);
|
|
124
159
|
}, [onMomentumScrollEnd]);
|
|
125
160
|
const handleLayout = (0, react_1.useCallback)((event) => {
|
|
@@ -129,12 +164,25 @@ exports.RepliqoScrollView = react_1.default.forwardRef(({ onScroll, onMomentumSc
|
|
|
129
164
|
scrollState.current = {
|
|
130
165
|
offsetY: 0,
|
|
131
166
|
viewportHeight: height,
|
|
132
|
-
contentHeight: height,
|
|
167
|
+
contentHeight: realContentHeight.current || height,
|
|
133
168
|
};
|
|
134
|
-
setTimeout(doCapture, 1000);
|
|
169
|
+
setTimeout(() => doCapture(), 1000);
|
|
135
170
|
}
|
|
136
171
|
onLayout?.(event);
|
|
137
172
|
}, [onLayout]);
|
|
138
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Track the real content height from onContentSizeChange.
|
|
175
|
+
* This is more reliable than the first scroll event and ensures
|
|
176
|
+
* the initial tile at Y=0 has correct contentHeight metadata.
|
|
177
|
+
*/
|
|
178
|
+
const handleContentSizeChange = (0, react_1.useCallback)((w, h) => {
|
|
179
|
+
realContentHeight.current = h;
|
|
180
|
+
// Update scroll state if it exists
|
|
181
|
+
if (scrollState.current) {
|
|
182
|
+
scrollState.current.contentHeight = h;
|
|
183
|
+
}
|
|
184
|
+
onContentSizeChange?.(w, h);
|
|
185
|
+
}, [onContentSizeChange]);
|
|
186
|
+
return (<react_native_1.ScrollView ref={ref} {...props} onScroll={handleScroll} onScrollEndDrag={handleScrollEndDrag} onMomentumScrollEnd={handleMomentumEnd} onLayout={handleLayout} onContentSizeChange={handleContentSizeChange} scrollEventThrottle={props.scrollEventThrottle ?? 16}/>);
|
|
139
187
|
});
|
|
140
188
|
exports.RepliqoScrollView.displayName = 'RepliqoScrollView';
|
package/dist/core/client.js
CHANGED
|
@@ -284,16 +284,14 @@ class AppAnalytics {
|
|
|
284
284
|
this.scrollOffsetY = 0;
|
|
285
285
|
this.errorTracker?.setCurrentScreen(screenName);
|
|
286
286
|
this.snapshotCapture?.setCurrentScreen(screenName);
|
|
287
|
-
//
|
|
288
|
-
//
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}, 2000);
|
|
296
|
-
}
|
|
287
|
+
// NOTE: autoScanScreen (PixelCopy / programmatic scroll) is DISABLED.
|
|
288
|
+
// React Native does NOT render off-screen content to the GPU or view
|
|
289
|
+
// tree, so programmatic scroll + View.draw()/PixelCopy produces blank
|
|
290
|
+
// tiles. Worse, those blank tiles poison the dedup cache and block
|
|
291
|
+
// real tiles captured during natural user scroll.
|
|
292
|
+
//
|
|
293
|
+
// Full-content capture relies entirely on RepliqoScrollView capturing
|
|
294
|
+
// viewport tiles as the user naturally scrolls through the content.
|
|
297
295
|
this.logger.log('Screen entered:', screenName);
|
|
298
296
|
}
|
|
299
297
|
onScreenExit(screenName) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@repliqo/sdk-react-native",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Session replay & analytics SDK for React Native. Captures screenshots (including modals/alerts), navigation, screen visits, and custom events.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,47 +11,60 @@ import { AppAnalytics } from '../core/client';
|
|
|
11
11
|
/** Minimum scroll delta (px) to trigger a new tile capture. */
|
|
12
12
|
const MIN_DELTA_PX = 20;
|
|
13
13
|
/** Debounce: wait this long after scroll stops before capturing. */
|
|
14
|
-
const DEBOUNCE_MS =
|
|
14
|
+
const DEBOUNCE_MS = 250;
|
|
15
15
|
/** Throttle: minimum time between tile captures. */
|
|
16
|
-
const THROTTLE_MS =
|
|
16
|
+
const THROTTLE_MS = 400;
|
|
17
|
+
/**
|
|
18
|
+
* During continuous scroll, force a capture every this many ms.
|
|
19
|
+
* Ensures tiles are captured even during fast, uninterrupted scrolls
|
|
20
|
+
* where the user never pauses long enough for the debounce to fire.
|
|
21
|
+
*/
|
|
22
|
+
const SCROLL_INTERVAL_MS = 1200;
|
|
17
23
|
|
|
18
24
|
/**
|
|
19
25
|
* Drop-in replacement for React Native's ScrollView that:
|
|
20
26
|
*
|
|
21
27
|
* 1. Reports scroll offset for accurate heatmap touch coords
|
|
22
|
-
* 2. Captures viewport tiles on scroll stops
|
|
23
|
-
* screen building — the backend composites
|
|
24
|
-
* full-content image over time
|
|
28
|
+
* 2. Captures viewport tiles on scroll stops AND during continuous
|
|
29
|
+
* scroll for collaborative screen building — the backend composites
|
|
30
|
+
* these into a full-content image over time
|
|
25
31
|
*/
|
|
26
32
|
export const RepliqoScrollView = React.forwardRef<ScrollView, ScrollViewProps>(
|
|
27
|
-
({ onScroll, onMomentumScrollEnd, onScrollEndDrag, onLayout, ...props }, ref) => {
|
|
33
|
+
({ onScroll, onMomentumScrollEnd, onScrollEndDrag, onLayout, onContentSizeChange, ...props }, ref) => {
|
|
28
34
|
const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
35
|
+
const scrollIntervalTimer = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
29
36
|
const lastCaptureTime = useRef(0);
|
|
30
37
|
const lastCaptureY = useRef(-999);
|
|
31
38
|
const initialCaptured = useRef(false);
|
|
39
|
+
const realContentHeight = useRef(0);
|
|
32
40
|
const scrollState = useRef<{
|
|
33
41
|
offsetY: number;
|
|
34
42
|
viewportHeight: number;
|
|
35
43
|
contentHeight: number;
|
|
36
44
|
} | null>(null);
|
|
37
45
|
|
|
38
|
-
// Cleanup
|
|
46
|
+
// Cleanup timers on unmount
|
|
39
47
|
useEffect(() => {
|
|
40
48
|
return () => {
|
|
41
49
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
50
|
+
if (scrollIntervalTimer.current) clearInterval(scrollIntervalTimer.current);
|
|
42
51
|
};
|
|
43
52
|
}, []);
|
|
44
53
|
|
|
45
54
|
/**
|
|
46
55
|
* Core tile capture logic. Reads from refs (stable across renders).
|
|
47
56
|
* Checks throttle + delta before capturing.
|
|
57
|
+
*
|
|
58
|
+
* @param force Skip throttle check (used for interval captures)
|
|
48
59
|
*/
|
|
49
|
-
const doCapture = () => {
|
|
60
|
+
const doCapture = (force = false) => {
|
|
50
61
|
const state = scrollState.current;
|
|
51
62
|
if (!state || state.viewportHeight <= 0) return;
|
|
52
63
|
|
|
53
64
|
const now = Date.now();
|
|
54
|
-
if (now - lastCaptureTime.current < THROTTLE_MS) return;
|
|
65
|
+
if (!force && now - lastCaptureTime.current < THROTTLE_MS) return;
|
|
66
|
+
|
|
67
|
+
// Always check delta — no point re-capturing the same position
|
|
55
68
|
if (Math.abs(state.offsetY - lastCaptureY.current) < MIN_DELTA_PX &&
|
|
56
69
|
initialCaptured.current) return;
|
|
57
70
|
|
|
@@ -68,6 +81,22 @@ export const RepliqoScrollView = React.forwardRef<ScrollView, ScrollViewProps>(
|
|
|
68
81
|
} catch {}
|
|
69
82
|
};
|
|
70
83
|
|
|
84
|
+
/** Start the interval timer for continuous scroll captures. */
|
|
85
|
+
const startScrollInterval = () => {
|
|
86
|
+
if (scrollIntervalTimer.current !== null) return;
|
|
87
|
+
scrollIntervalTimer.current = setInterval(() => {
|
|
88
|
+
doCapture(true); // force=true skips throttle
|
|
89
|
+
}, SCROLL_INTERVAL_MS);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/** Stop the interval timer. */
|
|
93
|
+
const stopScrollInterval = () => {
|
|
94
|
+
if (scrollIntervalTimer.current !== null) {
|
|
95
|
+
clearInterval(scrollIntervalTimer.current);
|
|
96
|
+
scrollIntervalTimer.current = null;
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
71
100
|
const handleScroll = useCallback(
|
|
72
101
|
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
73
102
|
const { contentOffset, layoutMeasurement, contentSize } =
|
|
@@ -78,20 +107,26 @@ export const RepliqoScrollView = React.forwardRef<ScrollView, ScrollViewProps>(
|
|
|
78
107
|
AppAnalytics.getInstance().setScrollOffset(contentOffset.y);
|
|
79
108
|
} catch {}
|
|
80
109
|
|
|
81
|
-
// Update scroll state
|
|
110
|
+
// Update scroll state — use realContentHeight if available
|
|
111
|
+
const bestContentHeight = realContentHeight.current > 0
|
|
112
|
+
? realContentHeight.current
|
|
113
|
+
: contentSize.height;
|
|
82
114
|
scrollState.current = {
|
|
83
115
|
offsetY: contentOffset.y,
|
|
84
116
|
viewportHeight: layoutMeasurement.height,
|
|
85
|
-
contentHeight:
|
|
117
|
+
contentHeight: bestContentHeight,
|
|
86
118
|
};
|
|
87
119
|
|
|
88
120
|
// Debounce: capture after scroll stops
|
|
89
121
|
if (debounceTimer.current) clearTimeout(debounceTimer.current);
|
|
90
|
-
debounceTimer.current = setTimeout(doCapture, DEBOUNCE_MS);
|
|
122
|
+
debounceTimer.current = setTimeout(() => doCapture(), DEBOUNCE_MS);
|
|
91
123
|
|
|
92
|
-
//
|
|
124
|
+
// Start interval for continuous scroll captures
|
|
125
|
+
startScrollInterval();
|
|
126
|
+
|
|
127
|
+
// Capture initial tile (Y~0) on first scroll event with real dims
|
|
93
128
|
if (!initialCaptured.current && contentOffset.y < 10) {
|
|
94
|
-
setTimeout(doCapture, 200);
|
|
129
|
+
setTimeout(() => doCapture(), 200);
|
|
95
130
|
}
|
|
96
131
|
|
|
97
132
|
onScroll?.(event);
|
|
@@ -102,7 +137,8 @@ export const RepliqoScrollView = React.forwardRef<ScrollView, ScrollViewProps>(
|
|
|
102
137
|
const handleScrollEndDrag = useCallback(
|
|
103
138
|
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
|
104
139
|
// User lifted finger — capture immediately
|
|
105
|
-
|
|
140
|
+
stopScrollInterval();
|
|
141
|
+
doCapture(true);
|
|
106
142
|
onScrollEndDrag?.(event);
|
|
107
143
|
},
|
|
108
144
|
[onScrollEndDrag],
|
|
@@ -114,7 +150,8 @@ export const RepliqoScrollView = React.forwardRef<ScrollView, ScrollViewProps>(
|
|
|
114
150
|
clearTimeout(debounceTimer.current);
|
|
115
151
|
debounceTimer.current = null;
|
|
116
152
|
}
|
|
117
|
-
|
|
153
|
+
stopScrollInterval();
|
|
154
|
+
doCapture(true);
|
|
118
155
|
onMomentumScrollEnd?.(event);
|
|
119
156
|
},
|
|
120
157
|
[onMomentumScrollEnd],
|
|
@@ -128,15 +165,32 @@ export const RepliqoScrollView = React.forwardRef<ScrollView, ScrollViewProps>(
|
|
|
128
165
|
scrollState.current = {
|
|
129
166
|
offsetY: 0,
|
|
130
167
|
viewportHeight: height,
|
|
131
|
-
contentHeight: height,
|
|
168
|
+
contentHeight: realContentHeight.current || height,
|
|
132
169
|
};
|
|
133
|
-
setTimeout(doCapture, 1000);
|
|
170
|
+
setTimeout(() => doCapture(), 1000);
|
|
134
171
|
}
|
|
135
172
|
onLayout?.(event);
|
|
136
173
|
},
|
|
137
174
|
[onLayout],
|
|
138
175
|
);
|
|
139
176
|
|
|
177
|
+
/**
|
|
178
|
+
* Track the real content height from onContentSizeChange.
|
|
179
|
+
* This is more reliable than the first scroll event and ensures
|
|
180
|
+
* the initial tile at Y=0 has correct contentHeight metadata.
|
|
181
|
+
*/
|
|
182
|
+
const handleContentSizeChange = useCallback(
|
|
183
|
+
(w: number, h: number) => {
|
|
184
|
+
realContentHeight.current = h;
|
|
185
|
+
// Update scroll state if it exists
|
|
186
|
+
if (scrollState.current) {
|
|
187
|
+
scrollState.current.contentHeight = h;
|
|
188
|
+
}
|
|
189
|
+
onContentSizeChange?.(w, h);
|
|
190
|
+
},
|
|
191
|
+
[onContentSizeChange],
|
|
192
|
+
);
|
|
193
|
+
|
|
140
194
|
return (
|
|
141
195
|
<ScrollView
|
|
142
196
|
ref={ref}
|
|
@@ -145,6 +199,7 @@ export const RepliqoScrollView = React.forwardRef<ScrollView, ScrollViewProps>(
|
|
|
145
199
|
onScrollEndDrag={handleScrollEndDrag}
|
|
146
200
|
onMomentumScrollEnd={handleMomentumEnd}
|
|
147
201
|
onLayout={handleLayout}
|
|
202
|
+
onContentSizeChange={handleContentSizeChange}
|
|
148
203
|
scrollEventThrottle={props.scrollEventThrottle ?? 16}
|
|
149
204
|
/>
|
|
150
205
|
);
|
package/src/core/client.ts
CHANGED
|
@@ -416,15 +416,14 @@ export class AppAnalytics {
|
|
|
416
416
|
this.scrollOffsetY = 0;
|
|
417
417
|
this.errorTracker?.setCurrentScreen(screenName);
|
|
418
418
|
this.snapshotCapture?.setCurrentScreen(screenName);
|
|
419
|
-
//
|
|
420
|
-
//
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
419
|
+
// NOTE: autoScanScreen (PixelCopy / programmatic scroll) is DISABLED.
|
|
420
|
+
// React Native does NOT render off-screen content to the GPU or view
|
|
421
|
+
// tree, so programmatic scroll + View.draw()/PixelCopy produces blank
|
|
422
|
+
// tiles. Worse, those blank tiles poison the dedup cache and block
|
|
423
|
+
// real tiles captured during natural user scroll.
|
|
424
|
+
//
|
|
425
|
+
// Full-content capture relies entirely on RepliqoScrollView capturing
|
|
426
|
+
// viewport tiles as the user naturally scrolls through the content.
|
|
428
427
|
|
|
429
428
|
this.logger.log('Screen entered:', screenName);
|
|
430
429
|
}
|