@akhilpulse/samadhaan-session-replay 0.4.0 → 0.4.1
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/README.md +15 -3
- package/package.json +1 -1
- package/src/SessionReplayProvider.tsx +76 -1
package/README.md
CHANGED
|
@@ -74,12 +74,24 @@ const { pause, resume, sessionId, status } = useSessionReplay();
|
|
|
74
74
|
|
|
75
75
|
### Shake-to-Assist (AI voice guide)
|
|
76
76
|
|
|
77
|
-
**New in 0.4.0.** The user
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
**New in 0.4.0.** The user opens the voice assistant, asks a question out loud
|
|
78
|
+
("how do I pay my bill?"), the AI looks at their current screen and draws an
|
|
79
|
+
**on-screen arrow** pointing at the next element to tap — step by step.
|
|
80
80
|
Works in **English and Hindi**. Every assistant session (questions + AI steps +
|
|
81
81
|
screenshots) is recorded and visible in the dashboard.
|
|
82
82
|
|
|
83
|
+
**New in 0.4.1 — floating help button (default trigger).** A small draggable
|
|
84
|
+
`?` button floats at the top-right of the screen. Tapping it starts the voice
|
|
85
|
+
guide; the user can drag it anywhere and it stays inside the screen. This is
|
|
86
|
+
the definitive trigger for **Expo** apps, where the native shake module isn't
|
|
87
|
+
available. Shake (if `react-native-shake` is installed) and `triggerAssist()`
|
|
88
|
+
still work as alternate triggers.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
// The button shows by default. To hide it:
|
|
92
|
+
<SessionReplayProvider config={{ appId: "app_xxx", showAssistButton: false }}>
|
|
93
|
+
```
|
|
94
|
+
|
|
83
95
|
```tsx
|
|
84
96
|
<SessionReplayProvider
|
|
85
97
|
config={{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akhilpulse/samadhaan-session-replay",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "React Native SDK for Samadhaan Guided Support — session recording, live remote screen-share, take-control, guided-tour overlays, and Shake-to-Assist AI voice guide.",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"module": "src/index.ts",
|
|
@@ -53,7 +53,7 @@ const SessionReplayPixelCopy: PixelCopyNative | undefined =
|
|
|
53
53
|
let pixelCopyDisabled = false; // turned true after a runtime failure to avoid retrying every frame
|
|
54
54
|
|
|
55
55
|
const STORAGE_KEY = "@akhilpulse/samadhaan-session-replay/sessionId";
|
|
56
|
-
const SDK_VERSION = "0.4.
|
|
56
|
+
const SDK_VERSION = "0.4.1";
|
|
57
57
|
|
|
58
58
|
// ---- Module-level session singleton --------------------------------------
|
|
59
59
|
// Multiple SessionReplayProvider mounts (intentional or via React StrictMode's
|
|
@@ -93,6 +93,12 @@ type Config = {
|
|
|
93
93
|
assistantLang?: "en" | "hi";
|
|
94
94
|
/** Disable the shake-to-assist voice guide entirely. */
|
|
95
95
|
disableAssistant?: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Show a small draggable floating help button (top-right) that opens the
|
|
98
|
+
* voice guide on tap. This is the definitive trigger for Expo apps where
|
|
99
|
+
* the native shake module isn't available. Default: true.
|
|
100
|
+
*/
|
|
101
|
+
showAssistButton?: boolean;
|
|
96
102
|
/**
|
|
97
103
|
* Optional streaming-PCM player for the agent's voice. Without it the
|
|
98
104
|
* assistant still listens + shows the on-screen arrow, but won't speak aloud.
|
|
@@ -671,6 +677,43 @@ export function SessionReplayProvider({ config, children }: { config: Config; ch
|
|
|
671
677
|
[endTourPan]
|
|
672
678
|
);
|
|
673
679
|
|
|
680
|
+
// ---- Draggable floating Assist help button (definitive trigger for Expo) ----
|
|
681
|
+
const assistFabPan = useRef(new Animated.ValueXY({ x: 0, y: 0 })).current;
|
|
682
|
+
const assistFabPanResponder = useMemo(
|
|
683
|
+
() =>
|
|
684
|
+
PanResponder.create({
|
|
685
|
+
// Don't claim taps — let the inner Pressable receive onPress.
|
|
686
|
+
onStartShouldSetPanResponder: () => false,
|
|
687
|
+
// Only claim once the user clearly starts dragging (>4px).
|
|
688
|
+
onMoveShouldSetPanResponder: (_e, g) => Math.abs(g.dx) > 4 || Math.abs(g.dy) > 4,
|
|
689
|
+
onPanResponderGrant: () => {
|
|
690
|
+
assistFabPan.extractOffset();
|
|
691
|
+
},
|
|
692
|
+
onPanResponderMove: Animated.event(
|
|
693
|
+
[null, { dx: assistFabPan.x, dy: assistFabPan.y }],
|
|
694
|
+
{ useNativeDriver: false }
|
|
695
|
+
),
|
|
696
|
+
onPanResponderRelease: () => {
|
|
697
|
+
assistFabPan.flattenOffset();
|
|
698
|
+
// Clamp inside the visible root-view bounds so the button never escapes off-screen.
|
|
699
|
+
const { w, h } = viewSizeRef.current;
|
|
700
|
+
const FAB = 44, ANCHOR_TOP = 96, ANCHOR_RIGHT = 12, MARGIN = 8;
|
|
701
|
+
const minX = -(Math.max(0, w - ANCHOR_RIGHT - FAB - MARGIN));
|
|
702
|
+
const maxX = 0;
|
|
703
|
+
const minY = -(ANCHOR_TOP - MARGIN);
|
|
704
|
+
const maxY = Math.max(0, h - ANCHOR_TOP - FAB - MARGIN);
|
|
705
|
+
const cx = (assistFabPan.x as any)._value;
|
|
706
|
+
const cy = (assistFabPan.y as any)._value;
|
|
707
|
+
const nx = Math.min(maxX, Math.max(minX, cx));
|
|
708
|
+
const ny = Math.min(maxY, Math.max(minY, cy));
|
|
709
|
+
if (nx !== cx || ny !== cy) {
|
|
710
|
+
Animated.spring(assistFabPan, { toValue: { x: nx, y: ny }, useNativeDriver: false, friction: 7 }).start();
|
|
711
|
+
}
|
|
712
|
+
},
|
|
713
|
+
}),
|
|
714
|
+
[assistFabPan]
|
|
715
|
+
);
|
|
716
|
+
|
|
674
717
|
function consentTour(accept: boolean) {
|
|
675
718
|
if (accept) {
|
|
676
719
|
setTourState((s) => ({ phase: "active", agentName: s.agentName }));
|
|
@@ -811,6 +854,25 @@ export function SessionReplayProvider({ config, children }: { config: Config; ch
|
|
|
811
854
|
);
|
|
812
855
|
})()}
|
|
813
856
|
|
|
857
|
+
{/* Floating help button — draggable, tap to open the AI voice guide.
|
|
858
|
+
This is the definitive trigger for Expo apps (no native shake module). */}
|
|
859
|
+
{!config.disableAssistant && config.showAssistButton !== false && !assistantActive && (
|
|
860
|
+
<Animated.View
|
|
861
|
+
style={[styles.assistFab, { transform: assistFabPan.getTranslateTransform() }]}
|
|
862
|
+
{...assistFabPanResponder.panHandlers}
|
|
863
|
+
>
|
|
864
|
+
<Pressable
|
|
865
|
+
onPress={() => startAssist()}
|
|
866
|
+
style={({ pressed }) => [styles.assistFabPressable, pressed && styles.btnPressed]}
|
|
867
|
+
hitSlop={8}
|
|
868
|
+
accessibilityRole="button"
|
|
869
|
+
accessibilityLabel="Open voice help"
|
|
870
|
+
>
|
|
871
|
+
<Text style={styles.assistFabIcon}>?</Text>
|
|
872
|
+
</Pressable>
|
|
873
|
+
</Animated.View>
|
|
874
|
+
)}
|
|
875
|
+
|
|
814
876
|
{/* Shake-to-Assist: bottom voice "wave" control + status. */}
|
|
815
877
|
{assistantActive && (
|
|
816
878
|
<View style={styles.assistDock} pointerEvents="box-none">
|
|
@@ -1029,6 +1091,19 @@ const styles = StyleSheet.create({
|
|
|
1029
1091
|
paddingVertical: 8, paddingHorizontal: 16, minHeight: 36, justifyContent: "center",
|
|
1030
1092
|
},
|
|
1031
1093
|
assistCloseText: { color: "#fff", fontSize: 14, fontWeight: "700" },
|
|
1094
|
+
assistFab: {
|
|
1095
|
+
position: "absolute", top: 96, right: 12,
|
|
1096
|
+
width: 44, height: 44, borderRadius: 22,
|
|
1097
|
+
shadowColor: "#000", shadowOpacity: 0.3, shadowRadius: 8, shadowOffset: { width: 0, height: 4 },
|
|
1098
|
+
elevation: 6,
|
|
1099
|
+
},
|
|
1100
|
+
assistFabPressable: {
|
|
1101
|
+
width: 44, height: 44, borderRadius: 22,
|
|
1102
|
+
backgroundColor: "#3b82f6",
|
|
1103
|
+
alignItems: "center", justifyContent: "center",
|
|
1104
|
+
borderWidth: 2, borderColor: "rgba(255,255,255,0.85)",
|
|
1105
|
+
},
|
|
1106
|
+
assistFabIcon: { color: "#fff", fontSize: 20, fontWeight: "800", lineHeight: 24 },
|
|
1032
1107
|
waveRow: { flexDirection: "row", alignItems: "center", height: 28, width: 44 },
|
|
1033
1108
|
waveBar: {
|
|
1034
1109
|
width: 4, height: 22, marginHorizontal: 2, borderRadius: 2, backgroundColor: "#60a5fa",
|