@robono/messaging-react-native 0.10.0 → 0.11.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/CHANGELOG.md +8 -0
- package/README.md +10 -1
- package/SBOM.spdx.json +26 -26
- package/dist/account.d.ts +3 -0
- package/dist/account.js +14 -4
- package/dist/expo-connected-calling.d.ts +8 -0
- package/dist/expo-connected-calling.js +4 -3
- package/dist/expo-messenger.d.ts +16 -0
- package/dist/expo-messenger.js +3 -1
- package/dist/popup.js +4 -3
- package/package.json +4 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
## 0.10.0 — release candidate
|
|
2
2
|
|
|
3
|
+
## 0.11.1
|
|
4
|
+
|
|
5
|
+
- Automatically install the shared calling UI package used by the account device-check panel, including chat-only installations. Native camera/calling dependencies remain optional.
|
|
6
|
+
|
|
7
|
+
## 0.11.0
|
|
8
|
+
|
|
9
|
+
Connects the supplied Messenger to recording/caption controls, on-device background blur and account device checks, using its existing call integration.
|
|
10
|
+
|
|
3
11
|
Add supplied business cards, public groups and moderation, appearance controls, app-wide availability and inbox continuity. Own conversation opening and foreground incoming updates inside ExpoMessenger. Expand supplied interface languages.
|
|
4
12
|
|
|
5
13
|
## 0.9.0 — release candidate
|
package/README.md
CHANGED
|
@@ -257,7 +257,7 @@ import { MessagingCallingScreen } from '@robono/messaging-react-native/calling';
|
|
|
257
257
|
/>
|
|
258
258
|
```
|
|
259
259
|
|
|
260
|
-
The
|
|
260
|
+
The shared `@robono/calling-react-native` UI package is installed automatically, including for the account device-check panel. Native call media and notification adapters remain optional. Mount the calling overlay and configure native audio/notifications through the existing calling integration. This entry creates no call client and requests no permission. Omit `onCall` to hide the action; backend admission remains authoritative. `MessagingHeader` also accepts children for custom header actions.
|
|
261
261
|
|
|
262
262
|
The website preview renders the same bubbles, inline voice controls, full-screen photo/file viewer and video transport controls through React Native Web. Phone/tablet and portrait/landscape choices resize the real layout viewport without reloading the conversation. Browser media elements and Expo players drive the shared controls; the browser preview does not substitute native browser player controls or a generic dialog. Camera/library/file selection and OS permission prompts still follow the platform. Preview interactions never contact real users or send billable events.
|
|
263
263
|
|
|
@@ -448,3 +448,12 @@ The complete Messenger connection supplies foreground activity independently of
|
|
|
448
448
|
the selected chat. Online now and optional Last seen are chosen in Features &
|
|
449
449
|
preview. `connection.availability` can also supply an authorized contact list.
|
|
450
450
|
[Activity setup, privacy and timing](https://robono.com/guides/user-availability.html).
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
## Recording, captions and local call tools
|
|
454
|
+
|
|
455
|
+
Robono hosts optional call recording and transcription. Enable recording once in the existing Calling settings; every participant must agree before capture, and anyone can stop it. The supplied controls include the consent notice, active-recording status and captions. No customer recording server is required.
|
|
456
|
+
|
|
457
|
+
The supplied adapters also offer camera/microphone/speaker checks and camera background blur. Screen sharing is separate. Phone blur requires rebuilding the native app; browser blur downloads its model only when selected and needs the documented content-security policy. Background processing stays on the device.
|
|
458
|
+
|
|
459
|
+
See the [recording and call tools guide](https://robono.com/guides/call-recording.html) for prices, retention, short-lived downloads, deletion, platform requirements and label customization. Captions arrive in short batches with several seconds of delay and can be inaccurate; incomplete transcripts are marked.
|
package/SBOM.spdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"spdxVersion": "SPDX-2.3",
|
|
3
3
|
"dataLicense": "CC0-1.0",
|
|
4
4
|
"SPDXID": "SPDXRef-DOCUMENT",
|
|
5
|
-
"name": "@robono/messaging-react-native@0.
|
|
6
|
-
"documentNamespace": "https://robono.com/sbom/messaging-react-native/0.
|
|
5
|
+
"name": "@robono/messaging-react-native@0.11.1",
|
|
6
|
+
"documentNamespace": "https://robono.com/sbom/messaging-react-native/0.11.1/286f4d0522c91da70b03b56bd0f6c1b2c04dfc1d",
|
|
7
7
|
"creationInfo": {
|
|
8
|
-
"created": "2026-11-
|
|
8
|
+
"created": "2026-11-05T16:05:58.060Z",
|
|
9
9
|
"creators": [
|
|
10
10
|
"Organization: Robono (support@robono.com)"
|
|
11
11
|
]
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
{
|
|
15
15
|
"name": "@robono/messaging-react-native",
|
|
16
16
|
"SPDXID": "SPDXRef-Package",
|
|
17
|
-
"versionInfo": "0.
|
|
17
|
+
"versionInfo": "0.11.1",
|
|
18
18
|
"downloadLocation": "NOASSERTION",
|
|
19
19
|
"filesAnalyzed": true,
|
|
20
20
|
"packageVerificationCode": {
|
|
21
|
-
"packageVerificationCodeValue": "
|
|
21
|
+
"packageVerificationCodeValue": "286f4d0522c91da70b03b56bd0f6c1b2c04dfc1d"
|
|
22
22
|
},
|
|
23
23
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
24
24
|
"licenseDeclared": "LicenseRef-RobonoSDK",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"LicenseRef-RobonoSDK"
|
|
27
27
|
],
|
|
28
28
|
"copyrightText": "Copyright (c) 2026 Add to Loop LLC.",
|
|
29
|
-
"comment": "Host-supplied peers (not bundled): {\"@robono/messaging\":\"^0.7.
|
|
29
|
+
"comment": "Host-supplied peers (not bundled): {\"@robono/messaging\":\"^0.7.1\",\"react\":\">=18.2 <20\",\"react-native\":\">=0.76 <1\",\"expo-audio\":\">=55 <57\",\"expo-image-picker\":\">=55 <57\",\"expo-document-picker\":\">=55 <57\",\"expo-file-system\":\">=55.0.5 <57\",\"expo-sharing\":\">=55 <57\",\"expo-video\":\">=55 <57\",\"expo-crypto\":\">=55 <57\",\"react-native-safe-area-context\":\">=5 <6\",\"react-native-svg\":\">=15 <16\",\"@robono/calling-react-native\":\"^0.9.0\",\"expo-clipboard\":\">=8 <57\",\"expo-image-manipulator\":\">=14 <57\",\"expo-video-thumbnails\":\">=14 <57\",\"react-native-webview\":\">=13 <14\",\"expo-blur\":\">=55 <57\",\"expo-notifications\":\">=55 <57\",\"expo-secure-store\":\">=55 <57\",\"@robono/location-react-native\":\"^0.4.0\",\"expo-location\":\">=55 <57\",\"expo-constants\":\">=55 <57\",\"@robono/location\":\"^0.4.0\",\"expo-haptics\":\">=55 <57\",\"@robono/calling\":\"^0.6.0\"}"
|
|
30
30
|
}
|
|
31
31
|
],
|
|
32
32
|
"files": [
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"checksums": [
|
|
37
37
|
{
|
|
38
38
|
"algorithm": "SHA256",
|
|
39
|
-
"checksumValue": "
|
|
39
|
+
"checksumValue": "e8eb4bd2858a2014e51054ae28adb47484ec1808f84f69f0627962c9f9be5d3f"
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
42
|
"algorithm": "SHA1",
|
|
43
|
-
"checksumValue": "
|
|
43
|
+
"checksumValue": "7127471a85e7dc8b947adfafbca2b8244d2e47c1"
|
|
44
44
|
}
|
|
45
45
|
],
|
|
46
46
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
@@ -74,11 +74,11 @@
|
|
|
74
74
|
"checksums": [
|
|
75
75
|
{
|
|
76
76
|
"algorithm": "SHA256",
|
|
77
|
-
"checksumValue": "
|
|
77
|
+
"checksumValue": "90ec61ecc2e49dc24e94f2f5be166fff96a6a9d5e43a547c63d063c304d31185"
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"algorithm": "SHA1",
|
|
81
|
-
"checksumValue": "
|
|
81
|
+
"checksumValue": "9b4494b4fb6e5087c85407fd0fb256a0b9e26ec9"
|
|
82
82
|
}
|
|
83
83
|
],
|
|
84
84
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
@@ -112,11 +112,11 @@
|
|
|
112
112
|
"checksums": [
|
|
113
113
|
{
|
|
114
114
|
"algorithm": "SHA256",
|
|
115
|
-
"checksumValue": "
|
|
115
|
+
"checksumValue": "837f6a3887d02c596f9fd2e5774a7920b3fb4c51d9f40019c64d4b1af3e233ca"
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
118
|
"algorithm": "SHA1",
|
|
119
|
-
"checksumValue": "
|
|
119
|
+
"checksumValue": "b936af0371f7c382903f2a2f7d847faeee5688e8"
|
|
120
120
|
}
|
|
121
121
|
],
|
|
122
122
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
@@ -131,11 +131,11 @@
|
|
|
131
131
|
"checksums": [
|
|
132
132
|
{
|
|
133
133
|
"algorithm": "SHA256",
|
|
134
|
-
"checksumValue": "
|
|
134
|
+
"checksumValue": "399340c0a4539b5918e1ce1265a0811c624e7401bf21e7d7328449cfbc2609d4"
|
|
135
135
|
},
|
|
136
136
|
{
|
|
137
137
|
"algorithm": "SHA1",
|
|
138
|
-
"checksumValue": "
|
|
138
|
+
"checksumValue": "cd14cf72b91bac56dfd5ba1bac94d7e5bf647f42"
|
|
139
139
|
}
|
|
140
140
|
],
|
|
141
141
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
@@ -454,11 +454,11 @@
|
|
|
454
454
|
"checksums": [
|
|
455
455
|
{
|
|
456
456
|
"algorithm": "SHA256",
|
|
457
|
-
"checksumValue": "
|
|
457
|
+
"checksumValue": "42e29921bce9f8ec264aa6ebcd20132a3c8adf14d1eeadb1a19648ebdd318303"
|
|
458
458
|
},
|
|
459
459
|
{
|
|
460
460
|
"algorithm": "SHA1",
|
|
461
|
-
"checksumValue": "
|
|
461
|
+
"checksumValue": "ca3c4c7fc708e9d1eaa81850c7b11fa21dbd419b"
|
|
462
462
|
}
|
|
463
463
|
],
|
|
464
464
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
@@ -473,11 +473,11 @@
|
|
|
473
473
|
"checksums": [
|
|
474
474
|
{
|
|
475
475
|
"algorithm": "SHA256",
|
|
476
|
-
"checksumValue": "
|
|
476
|
+
"checksumValue": "398e93c24289d0c125acab0557a35c63b1fee9149137006568fefed0830b264a"
|
|
477
477
|
},
|
|
478
478
|
{
|
|
479
479
|
"algorithm": "SHA1",
|
|
480
|
-
"checksumValue": "
|
|
480
|
+
"checksumValue": "cb781c3a18e5e5e004219816735809d21a3fd970"
|
|
481
481
|
}
|
|
482
482
|
],
|
|
483
483
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
@@ -644,11 +644,11 @@
|
|
|
644
644
|
"checksums": [
|
|
645
645
|
{
|
|
646
646
|
"algorithm": "SHA256",
|
|
647
|
-
"checksumValue": "
|
|
647
|
+
"checksumValue": "2663ea07823c8dd95db571753c56ec4e655d9ae0cf66fb086b91ed6a50a0a8cc"
|
|
648
648
|
},
|
|
649
649
|
{
|
|
650
650
|
"algorithm": "SHA1",
|
|
651
|
-
"checksumValue": "
|
|
651
|
+
"checksumValue": "08d09268b8fc87e2a79666b09336e3310419d897"
|
|
652
652
|
}
|
|
653
653
|
],
|
|
654
654
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
@@ -663,11 +663,11 @@
|
|
|
663
663
|
"checksums": [
|
|
664
664
|
{
|
|
665
665
|
"algorithm": "SHA256",
|
|
666
|
-
"checksumValue": "
|
|
666
|
+
"checksumValue": "2656d4f7e8004333e73215709b6d4f84175a13ea476508e4965da8c1164aaf62"
|
|
667
667
|
},
|
|
668
668
|
{
|
|
669
669
|
"algorithm": "SHA1",
|
|
670
|
-
"checksumValue": "
|
|
670
|
+
"checksumValue": "66b634d4434e5a8e676977684e8658456d18deb0"
|
|
671
671
|
}
|
|
672
672
|
],
|
|
673
673
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
@@ -1955,11 +1955,11 @@
|
|
|
1955
1955
|
"checksums": [
|
|
1956
1956
|
{
|
|
1957
1957
|
"algorithm": "SHA256",
|
|
1958
|
-
"checksumValue": "
|
|
1958
|
+
"checksumValue": "ef2a8fdc3bc77bf6720d2ff806c935ad381889ff9e334ce0aa0be6e9d079b0c1"
|
|
1959
1959
|
},
|
|
1960
1960
|
{
|
|
1961
1961
|
"algorithm": "SHA1",
|
|
1962
|
-
"checksumValue": "
|
|
1962
|
+
"checksumValue": "d015990df7071695bf07c2367f9531fe37fc8f24"
|
|
1963
1963
|
}
|
|
1964
1964
|
],
|
|
1965
1965
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
|
@@ -2791,11 +2791,11 @@
|
|
|
2791
2791
|
"checksums": [
|
|
2792
2792
|
{
|
|
2793
2793
|
"algorithm": "SHA256",
|
|
2794
|
-
"checksumValue": "
|
|
2794
|
+
"checksumValue": "c16920f6704af714341e52f4415bc4ec66f1e181330773be404d0946efc8d500"
|
|
2795
2795
|
},
|
|
2796
2796
|
{
|
|
2797
2797
|
"algorithm": "SHA1",
|
|
2798
|
-
"checksumValue": "
|
|
2798
|
+
"checksumValue": "6291ed16a2896e9a7be69ce43a7eee4784e526bd"
|
|
2799
2799
|
}
|
|
2800
2800
|
],
|
|
2801
2801
|
"licenseConcluded": "LicenseRef-RobonoSDK",
|
package/dist/account.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { type CallDeviceCheck } from '@robono/calling-react-native';
|
|
1
2
|
import React from 'react';
|
|
2
3
|
/** Profile and account actions belong to the customer's sign-in system. */
|
|
3
4
|
export interface MessagingAccount {
|
|
5
|
+
deviceCheck?: CallDeviceCheck;
|
|
6
|
+
renderCallPreview?: (stream: MediaStream) => React.ReactNode;
|
|
4
7
|
name: string;
|
|
5
8
|
avatarUrl?: string;
|
|
6
9
|
phone?: string;
|
package/dist/account.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { CallDeviceCheckPanel, callDeviceCheckText } from '@robono/calling-react-native';
|
|
2
3
|
import { Text } from './typography.js';
|
|
3
4
|
import { useRobonoLocale } from './localization.js';
|
|
4
5
|
import { useEffect, useRef, useState } from 'react';
|
|
5
|
-
import { Image, Platform, Pressable, ScrollView, View } from 'react-native';
|
|
6
|
+
import { AppState, Image, Platform, Pressable, ScrollView, View } from 'react-native';
|
|
6
7
|
import { MessagingPopup, messagingPopupColors as c } from './popup.js';
|
|
7
8
|
import { MessageIcon } from './icons.js';
|
|
8
9
|
export function MessagingAccountScreen({ account, companyName, onClose }) {
|
|
9
10
|
const { text: uiText, locale: uiLocale, number: uiNumber, count: uiCount } = useRobonoLocale();
|
|
11
|
+
const [checking, setChecking] = useState(false);
|
|
12
|
+
useEffect(() => { const sub = AppState.addEventListener('change', value => { if (value !== 'active')
|
|
13
|
+
void account?.deviceCheck?.close(); }); return () => { sub.remove(); void account?.deviceCheck?.close(); }; }, [account?.deviceCheck]);
|
|
10
14
|
const [busy, setBusy] = useState(false), [error, setError] = useState(''), [visible, setVisible] = useState(true), pending = useRef(null);
|
|
11
15
|
const dismissed = () => { const action = pending.current; pending.current = null; if (action)
|
|
12
16
|
requestAnimationFrame(() => void run(action)); };
|
|
@@ -25,6 +29,12 @@ export function MessagingAccountScreen({ account, companyName, onClose }) {
|
|
|
25
29
|
finally {
|
|
26
30
|
setBusy(false);
|
|
27
31
|
} };
|
|
28
|
-
return _jsx(MessagingPopup, { visible: visible, onDismiss: dismissed, title: uiText("Account"), closeLabel: uiText("Close account"), closeDisabled: busy, background: c.background, contentWidth: 640, onClose: () => { if (!busy)
|
|
29
|
-
|
|
32
|
+
return _jsx(MessagingPopup, { visible: visible, onDismiss: dismissed, title: uiText(checking ? "Check call devices" : "Account"), headerBack: checking, closeLabel: uiText("Close account"), closeDisabled: busy, background: c.background, contentWidth: 640, onClose: () => { if (!busy) {
|
|
33
|
+
if (checking) {
|
|
34
|
+
void account?.deviceCheck?.close();
|
|
35
|
+
setChecking(false);
|
|
36
|
+
}
|
|
37
|
+
else
|
|
38
|
+
onClose();
|
|
39
|
+
} }, children: _jsx(ScrollView, { contentContainerStyle: { gap: 16, paddingBottom: 12 }, children: checking && account?.deviceCheck ? _jsx(CallDeviceCheckPanel, { check: account.deviceCheck, renderVideo: account.renderCallPreview, labels: Object.fromEntries(Object.entries(callDeviceCheckText).map(([key, value]) => [key, uiText(value)])) }) : _jsxs(_Fragment, { children: [_jsxs(View, { style: { backgroundColor: '#111111', borderRadius: 16, padding: 16, gap: 14 }, children: [_jsxs(View, { style: { flexDirection: 'row', alignItems: 'center', gap: 14 }, children: [account?.avatarUrl ? _jsx(Image, { source: { uri: account.avatarUrl }, style: { width: 56, height: 56, borderRadius: 28 } }) : _jsx(View, { style: { width: 56, height: 56, borderRadius: 28, backgroundColor: '#252525', alignItems: 'center', justifyContent: 'center' }, children: _jsx(MessageIcon, { name: "person-circle-outline", color: c.foreground, size: 36 }) }), _jsxs(View, { style: { flex: 1, gap: 4 }, children: [_jsx(Text, { style: { color: c.foreground, fontSize: 20, fontWeight: '600' }, children: account?.name ?? uiText("Your account") }), _jsx(Text, { style: { color: c.secondary, fontSize: 14 }, children: companyName })] })] }), account?.phone && _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: account.phone }), account?.email && _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: account.email }), account?.onEditProfile && _jsxs(Pressable, { accessibilityRole: "button", accessibilityLabel: uiText("Edit profile"), disabled: busy, onPress: () => begin(account.onEditProfile), style: { minHeight: 44, flexDirection: 'row', alignItems: 'center', gap: 10 }, children: [_jsx(MessageIcon, { name: "edit", color: c.foreground, size: 20 }), _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: uiText("Edit profile") })] })] }), account?.deviceCheck && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: uiText("Check call devices"), disabled: busy, onPress: () => setChecking(true), style: { backgroundColor: '#111111', borderRadius: 12, minHeight: 52, paddingHorizontal: 16, justifyContent: 'center' }, children: _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: uiText("Check call devices") }) }), account?.onEnableNotifications && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: uiText("Enable notifications"), disabled: busy, onPress: () => void run(account.onEnableNotifications), style: { backgroundColor: '#111111', borderRadius: 12, minHeight: 52, paddingHorizontal: 16, justifyContent: 'center' }, children: _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: uiText("Enable notifications") }) }), account?.onSignOut && _jsx(Pressable, { accessibilityRole: "button", accessibilityLabel: uiText("Sign out"), disabled: busy, onPress: () => begin(account.onSignOut), style: { backgroundColor: '#111111', borderRadius: 12, minHeight: 52, paddingHorizontal: 16, justifyContent: 'center' }, children: _jsx(Text, { style: { color: c.foreground, fontSize: 16 }, children: uiText("Sign out") }) }), !!error && _jsx(Text, { accessibilityRole: "alert", style: { color: c.foreground, fontSize: 15 }, children: error })] }) }) });
|
|
30
40
|
}
|
|
@@ -18,6 +18,14 @@ export declare function createExpoMessengerCalling(options: {
|
|
|
18
18
|
name: string;
|
|
19
19
|
avatarUrl?: string;
|
|
20
20
|
}>): void;
|
|
21
|
+
deviceCheck: {
|
|
22
|
+
getSnapshot: () => import("@robono/calling-react-native").CallDeviceCheckState;
|
|
23
|
+
subscribe(fn: () => void): () => void;
|
|
24
|
+
start(kind?: "voice" | "video"): Promise<void>;
|
|
25
|
+
speaker(): Promise<void>;
|
|
26
|
+
close: () => Promise<void>;
|
|
27
|
+
dispose(): Promise<void>;
|
|
28
|
+
} | undefined;
|
|
21
29
|
start: () => Promise<void>;
|
|
22
30
|
getSnapshot: () => MessengerCallingState;
|
|
23
31
|
subscribe(fn: () => void): () => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { callDiagnosticsText } from '@robono/calling-react-native';
|
|
2
|
+
import { callDiagnosticsText, callRecordingText } from '@robono/calling-react-native';
|
|
3
3
|
import { Text } from './typography.js';
|
|
4
4
|
import { callingText } from '@robono/calling-react-native/appearance';
|
|
5
5
|
import { useRobonoLocale } from './localization.js';
|
|
@@ -7,7 +7,7 @@ import { useEffect, useSyncExternalStore } from 'react';
|
|
|
7
7
|
import { Pressable, View } from 'react-native';
|
|
8
8
|
import { setAudioModeAsync } from 'expo-audio';
|
|
9
9
|
import { createMessengerCalling } from '@robono/calling-react-native/messenger';
|
|
10
|
-
import { createNativeCallAdapters } from '@robono/calling-react-native/native';
|
|
10
|
+
import { createNativeCallAdapters, createNativeCallDeviceCheck } from '@robono/calling-react-native/native';
|
|
11
11
|
import { createNativeCallRuntime } from '@robono/calling-react-native/runtime';
|
|
12
12
|
import { createNativeSystemCalling } from '@robono/calling-react-native/system-calling';
|
|
13
13
|
import { NativeCallingOverlay, NativeGroupCallingOverlay } from '@robono/calling-react-native/native-video';
|
|
@@ -18,6 +18,7 @@ export function createExpoMessengerCalling(options) {
|
|
|
18
18
|
let people = {};
|
|
19
19
|
const system = createNativeSystemCalling({ start: () => calling.start(), onError: () => calling.reportError('The incoming call could not connect. Open the app and check microphone access and your connection.') });
|
|
20
20
|
const calling = createMessengerCalling({
|
|
21
|
+
deviceCheck: active => createNativeCallDeviceCheck({ active, restoreAudio: () => setAudioModeAsync({ allowsRecording: false, playsInSilentMode: true, shouldPlayInBackground: false, shouldRouteThroughEarpiece: false, interruptionMode: 'mixWithOthers' }) }),
|
|
21
22
|
request: createMessagingTransport({ ...options, url: url.href }),
|
|
22
23
|
resolveContact: id => {
|
|
23
24
|
const row = options.inbox.getSnapshot().conversations.find(c => c.id === id);
|
|
@@ -54,5 +55,5 @@ export function useExpoMessengerCalling(calling) {
|
|
|
54
55
|
}
|
|
55
56
|
export function ExpoMessengerCalls({ calling, state }) {
|
|
56
57
|
const { text: uiText, locale: uiLocale, number: uiNumber, count: uiCount } = useRobonoLocale();
|
|
57
|
-
return _jsxs(_Fragment, { children: [state.error && _jsxs(View, { style: { backgroundColor: '#171717', paddingHorizontal: 16, paddingVertical: 8, flexDirection: 'row', gap: 12, alignItems: 'center' }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: '#FAFAFA', flex: 1 }, children: state.error }), _jsx(Pressable, { accessibilityRole: "button", onPress: () => void calling?.start().catch(() => { }), style: { padding: 8 }, children: _jsx(Text, { style: { color: '#FF8A2C' }, children: uiText("Retry calls") }) })] }), state.direct && _jsx(NativeCallingOverlay, { controller: state.direct, diagnostics: { labels: Object.fromEntries(Object.entries(callDiagnosticsText).map(([key, value]) => [key, uiText(value)])) }, appearance: state.appearance, labels: Object.fromEntries(Object.entries({ ...callingText, ...state.appearance?.labels }).map(([key, value]) => [key, uiText(value)])) }), state.group && _jsx(NativeGroupCallingOverlay, { controller: state.group, diagnostics: { labels: Object.fromEntries(Object.entries(callDiagnosticsText).map(([key, value]) => [key, uiText(value)])) }, appearance: state.appearance, labels: Object.fromEntries(Object.entries({ ...callingText, ...state.appearance?.labels }).map(([key, value]) => [key, uiText(value)])) })] });
|
|
58
|
+
return _jsxs(_Fragment, { children: [state.error && _jsxs(View, { style: { backgroundColor: '#171717', paddingHorizontal: 16, paddingVertical: 8, flexDirection: 'row', gap: 12, alignItems: 'center' }, children: [_jsx(Text, { accessibilityRole: "alert", style: { color: '#FAFAFA', flex: 1 }, children: state.error }), _jsx(Pressable, { accessibilityRole: "button", onPress: () => void calling?.start().catch(() => { }), style: { padding: 8 }, children: _jsx(Text, { style: { color: '#FF8A2C' }, children: uiText("Retry calls") }) })] }), state.direct && _jsx(NativeCallingOverlay, { controller: state.direct, recordingLabels: Object.fromEntries(Object.entries(callRecordingText).map(([key, value]) => [key, uiText(value)])), diagnostics: { labels: Object.fromEntries(Object.entries(callDiagnosticsText).map(([key, value]) => [key, uiText(value)])) }, appearance: state.appearance, labels: Object.fromEntries(Object.entries({ ...callingText, ...state.appearance?.labels }).map(([key, value]) => [key, uiText(value)])) }), state.group && _jsx(NativeGroupCallingOverlay, { controller: state.group, recordingLabels: Object.fromEntries(Object.entries(callRecordingText).map(([key, value]) => [key, uiText(value)])), diagnostics: { labels: Object.fromEntries(Object.entries(callDiagnosticsText).map(([key, value]) => [key, uiText(value)])) }, appearance: state.appearance, labels: Object.fromEntries(Object.entries({ ...callingText, ...state.appearance?.labels }).map(([key, value]) => [key, uiText(value)])) })] });
|
|
58
59
|
}
|
package/dist/expo-messenger.d.ts
CHANGED
|
@@ -46,6 +46,14 @@ export declare function createExpoMessenger(options: {
|
|
|
46
46
|
name: string;
|
|
47
47
|
avatarUrl?: string;
|
|
48
48
|
}>): void;
|
|
49
|
+
deviceCheck: {
|
|
50
|
+
getSnapshot: () => import("@robono/calling-react-native").CallDeviceCheckState;
|
|
51
|
+
subscribe(fn: () => void): () => void;
|
|
52
|
+
start(kind?: "voice" | "video"): Promise<void>;
|
|
53
|
+
speaker(): Promise<void>;
|
|
54
|
+
close: () => Promise<void>;
|
|
55
|
+
dispose(): Promise<void>;
|
|
56
|
+
} | undefined;
|
|
49
57
|
start: () => Promise<void>;
|
|
50
58
|
getSnapshot: () => import("@robono/calling-react-native/messenger").MessengerCallingState;
|
|
51
59
|
subscribe(fn: () => void): () => void;
|
|
@@ -83,6 +91,14 @@ export declare function createHostedExpoMessenger(options: Omit<Parameters<typeo
|
|
|
83
91
|
name: string;
|
|
84
92
|
avatarUrl?: string;
|
|
85
93
|
}>): void;
|
|
94
|
+
deviceCheck: {
|
|
95
|
+
getSnapshot: () => import("@robono/calling-react-native").CallDeviceCheckState;
|
|
96
|
+
subscribe(fn: () => void): () => void;
|
|
97
|
+
start(kind?: "voice" | "video"): Promise<void>;
|
|
98
|
+
speaker(): Promise<void>;
|
|
99
|
+
close: () => Promise<void>;
|
|
100
|
+
dispose(): Promise<void>;
|
|
101
|
+
} | undefined;
|
|
86
102
|
start: () => Promise<void>;
|
|
87
103
|
getSnapshot: () => import("@robono/calling-react-native/messenger").MessengerCallingState;
|
|
88
104
|
subscribe(fn: () => void): () => void;
|
package/dist/expo-messenger.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { renderNativeCallVideo } from '@robono/calling-react-native/native-video';
|
|
2
3
|
import { createInboxViewMemory } from './inbox-view.js';
|
|
3
4
|
import { MessagingPublicRooms } from './public-rooms.js';
|
|
4
5
|
import { RobonoLocaleProvider, useRobonoLocale } from './localization.js';
|
|
@@ -171,7 +172,8 @@ function ExpoMessengerContent({ inbox, contacts = {}, initialConversation, selec
|
|
|
171
172
|
};
|
|
172
173
|
useEffect(() => { void notifications?.start(async (id, message) => { await inbox.refresh(); const row = inbox.getSnapshot().conversations.find(c => c.id === id); if (row)
|
|
173
174
|
open(row, message); }).catch(() => { }); }, [notifications, inbox]);
|
|
174
|
-
const
|
|
175
|
+
const notificationAccount = notifications ? { name: props.account?.name ?? 'Your account', ...props.account, onEnableNotifications: () => notifications.enable() } : props.account;
|
|
176
|
+
const account = calling?.deviceCheck ? { name: 'Your account', ...notificationAccount, deviceCheck: calling.deviceCheck, renderCallPreview: (stream) => renderNativeCallVideo({ stream, local: true, style: { width: '100%', height: '100%' } }) } : notificationAccount;
|
|
175
177
|
const contact = selected?.kind === 'group' ? { name: selected.name ?? 'Group' } : contacts[selected?.contactId ?? ''] ?? { name: selected?.contactId ?? 'Chat' };
|
|
176
178
|
return _jsxs(View, { style: { flex: 1, minHeight: 0 }, children: [_jsx(MessengerMapsNotice, { error: mapConnection.error, retry: mapConnection.retry }), showMaps && maps ? _jsx(RobonoMaps, { interfaceLocale: mapsLocale, workspace: maps, contacts: contacts, onClose: () => setShowMaps(false) }) : _jsx(ExpoMessagingScreen, { ...props, account: account, contact: contact, participants: props.participants ?? contacts, extras: selected ? props.extras : undefined, callActions: selected ? { ...autoCalls, ...props.callActions, phoneNumber: contacts[selected.contactId ?? '']?.phoneNumber ?? props.callActions?.phoneNumber } : undefined, onBack: () => { props.client.stop(); setSelected(null); void inbox.refresh().catch(() => { }); }, renderConversation: screen => selected ? _jsx(MessagingCallingScreen, { ...screen, onCall: screen.callActions?.voice, onVideoCall: screen.callActions?.video, callLabel: "Internet call", unansweredCallId: callState.unanswered?.conversationId === selected.id ? callState.unanswered.id : undefined, onDismissCallMessage: calling?.dismissUnanswered }) : _jsxs(MessagingProvider, { ...screen, children: [_jsx(MessagingInbox, { viewMemory: inboxMemory, client: inbox, userId: props.userId, contacts: contacts, companyName: props.companyName, appearance: props.appearance, active: props.active !== false, headerActions: _jsx(MessagingAccountMenu, { onPublicRooms: inboxState.publicRoomsAvailable ? () => setPublicRooms(true) : undefined, onMaps: mapsAvailable ? () => setShowMaps(true) : undefined, onNewGroup: inboxState.groupCreationAvailable ? () => setNewGroup(true) : undefined }), onSelect: open, onDeleted: id => props.client.forgetConversation(id) }), publicRooms && _jsx(MessagingPublicRooms, { inbox: inbox, accent: (props.appearance ?? inboxState.appearance ?? defaultMessagingSettings().appearance).colors.accent, createRequestId: () => props.client.createForwardId(), onClose: () => setPublicRooms(false), onJoined: (id, name) => { setPublicRooms(false); open(inbox.getSnapshot().conversations.find(c => c.id === id) ?? { id, kind: 'group', name, contactId: null, lastMessage: null, unreadCount: 0, canSend: true }); } }), newGroup && _jsx(MessagingGroupEditor, { client: props.client, inbox: inbox, userId: props.userId, contacts: contacts, groups: inboxState.groups, accent: (props.appearance ?? inboxState.appearance ?? defaultMessagingSettings().appearance).colors.accent, onClose: () => setNewGroup(false), onSaved: (id, name) => { setNewGroup(false); const row = inbox.getSnapshot().conversations.find(c => c.id === id) ?? { id, kind: 'group', name, contactId: null, lastMessage: null, unreadCount: 0, canSend: true }; open(row); } })] }) }), _jsx(ExpoMessengerCalls, { calling: calling, state: callState })] });
|
|
177
179
|
}
|
package/dist/popup.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { SafeAreaInsetsContext } from 'react-native-safe-area-context';
|
|
2
3
|
import { Text } from './typography.js';
|
|
3
4
|
import { useRobonoLocale } from './localization.js';
|
|
4
5
|
import { createContext, useContext, useEffect, useLayoutEffect, useRef, useState, useCallback, useMemo } from 'react';
|
|
5
|
-
import { Keyboard, KeyboardAvoidingView, Modal, Platform, Pressable, SafeAreaView, View, useWindowDimensions } from 'react-native';
|
|
6
|
+
import { Keyboard, KeyboardAvoidingView, Modal, Platform, Pressable, SafeAreaView, StatusBar, View, useWindowDimensions } from 'react-native';
|
|
6
7
|
import { MessageIcon } from './icons.js';
|
|
7
8
|
/** Browser hosts can keep settings dialogs inside their embedded chat. */
|
|
8
9
|
export const MessagingPopupSurface = createContext(null);
|
|
@@ -97,7 +98,7 @@ export function MessagingMenuSurface({ visible, onClose, onDismiss, children })
|
|
|
97
98
|
}
|
|
98
99
|
/** Content panels occupy the area below the persistent header; confirmations stay compact. */
|
|
99
100
|
export function MessagingPopup({ children, onClose, background, form = false, visible = true, onDismiss, expanded = true, bottomPadding, title, foreground, closeLabel, closeDisabled = false, contentWidth, headerBack = false, withinChat = false, compact = false }) {
|
|
100
|
-
const ChatSurface = useContext(MessagingPopupSurface), bounds = useContext(PopupBounds), viewport = useWindowDimensions();
|
|
101
|
+
const ChatSurface = useContext(MessagingPopupSurface), bounds = useContext(PopupBounds), viewport = useWindowDimensions(), safeInsets = useContext(SafeAreaInsetsContext);
|
|
101
102
|
const [rect, setRect] = useState(null);
|
|
102
103
|
useLayoutEffect(() => {
|
|
103
104
|
if (!visible || Platform.OS === 'web' || !bounds)
|
|
@@ -139,7 +140,7 @@ export function MessagingPopup({ children, onClose, background, form = false, vi
|
|
|
139
140
|
} }; document.addEventListener('keydown', escape, true); return () => document.removeEventListener('keydown', escape, true); }, [visible]);
|
|
140
141
|
const bounded = Platform.OS !== 'web' && !!bounds;
|
|
141
142
|
const Frame = Platform.OS === 'ios' && !bounded ? SafeAreaView : View;
|
|
142
|
-
const content = _jsx(Frame, { style: [{ flex: 1, backgroundColor: messagingPopupBackdrop }, bounded ? { position: 'absolute', ...(rect ?? { left: 0, top: 0, width: 0, height: 0 }) } : undefined], children: _jsxs(KeyboardAvoidingView, { testID: "messaging-popup-backdrop", behavior: Platform.OS === 'ios' ? 'padding' : undefined, style: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: compact ? 24 : 8 }, children: [_jsx(Pressable, { accessible: false, onPress: onClose, style: { position: 'absolute', inset: 0 } }), _jsxs(View, { testID: "messaging-popup-panel", accessibilityViewIsModal: true, onAccessibilityEscape: onClose, style: { width: '100%', ...(compact ? { maxWidth: 360, maxHeight: '100%', flexShrink: 1 } : { flex: 1, minHeight: 0 }), backgroundColor: compact ? '#111111' : messagingPopupColors.background, borderRadius: compact ? 20 : 18, paddingHorizontal: compact ? 20 : 8, paddingTop: compact ? 8 : 0, paddingBottom: bottomPadding ?? (compact ? 20 : 4), overflow: 'hidden' }, children: [title && _jsx(MessagingPopupHeader, { title: title, foreground: messagingPopupColors.foreground, onClose: onClose, closeLabel: closeLabel, disabled: closeDisabled, back: headerBack }), contentWidth ? _jsx(View, { style: { ...(compact ? { flexShrink: 1 } : { flex: 1, minHeight: 0 }), width: '100%', maxWidth: contentWidth, alignSelf: 'center', paddingTop: 12 }, children: children }) : children] })] }) });
|
|
143
|
+
const content = _jsx(Frame, { style: [{ flex: 1, backgroundColor: messagingPopupBackdrop }, bounded ? { position: 'absolute', ...(rect ?? { left: 0, top: 0, width: 0, height: 0 }) } : Platform.OS === 'android' ? { paddingTop: safeInsets?.top ?? StatusBar.currentHeight ?? 0, paddingBottom: safeInsets?.bottom ?? 0 } : undefined], children: _jsxs(KeyboardAvoidingView, { testID: "messaging-popup-backdrop", behavior: Platform.OS === 'ios' ? 'padding' : undefined, style: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: compact ? 24 : 8 }, children: [_jsx(Pressable, { accessible: false, onPress: onClose, style: { position: 'absolute', inset: 0 } }), _jsxs(View, { testID: "messaging-popup-panel", accessibilityViewIsModal: true, onAccessibilityEscape: onClose, style: { width: '100%', ...(compact ? { maxWidth: 360, maxHeight: '100%', flexShrink: 1 } : { flex: 1, minHeight: 0 }), backgroundColor: compact ? '#111111' : messagingPopupColors.background, borderRadius: compact ? 20 : 18, paddingHorizontal: compact ? 20 : 8, paddingTop: compact ? 8 : 0, paddingBottom: bottomPadding ?? (compact ? 20 : 4), overflow: 'hidden' }, children: [title && _jsx(MessagingPopupHeader, { title: title, foreground: messagingPopupColors.foreground, onClose: onClose, closeLabel: closeLabel, disabled: closeDisabled, back: headerBack }), contentWidth ? _jsx(View, { style: { ...(compact ? { flexShrink: 1 } : { flex: 1, minHeight: 0 }), width: '100%', maxWidth: contentWidth, alignSelf: 'center', paddingTop: 12 }, children: children }) : children] })] }) });
|
|
143
144
|
if (Platform.OS === 'web' && ChatSurface)
|
|
144
145
|
return _jsx(ChatSurface, { visible: visible, title: title, onDismiss: onDismiss, onClose: onClose, children: content });
|
|
145
146
|
return _jsx(Modal, { visible: visible, statusBarTranslucent: true, navigationBarTranslucent: true, onDismiss: onDismiss, transparent: true, animationType: "fade", onRequestClose: onClose, children: content });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robono/messaging-react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Optional, composable direct and group messaging screens for Robono.",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"prepack": "npm run build && node ../../scripts/generate-sdk-file-sbom.mjs"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@robono/messaging": "^0.7.
|
|
58
|
+
"@robono/messaging": "^0.7.1",
|
|
59
59
|
"react": ">=18.2 <20",
|
|
60
60
|
"react-native": ">=0.76 <1",
|
|
61
61
|
"expo-audio": ">=55 <57",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"expo-crypto": ">=55 <57",
|
|
68
68
|
"react-native-safe-area-context": ">=5 <6",
|
|
69
69
|
"react-native-svg": ">=15 <16",
|
|
70
|
-
"@robono/calling-react-native": "^0.
|
|
70
|
+
"@robono/calling-react-native": "^0.9.0",
|
|
71
71
|
"expo-clipboard": ">=8 <57",
|
|
72
72
|
"expo-image-manipulator": ">=14 <57",
|
|
73
73
|
"expo-video-thumbnails": ">=14 <57",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"expo-constants": ">=55 <57",
|
|
81
81
|
"@robono/location": "^0.4.0",
|
|
82
82
|
"expo-haptics": ">=55 <57",
|
|
83
|
-
"@robono/calling": "^0.
|
|
83
|
+
"@robono/calling": "^0.6.0"
|
|
84
84
|
},
|
|
85
85
|
"license": "SEE LICENSE IN LICENSE",
|
|
86
86
|
"peerDependenciesMeta": {
|
|
@@ -108,9 +108,6 @@
|
|
|
108
108
|
"react-native-safe-area-context": {
|
|
109
109
|
"optional": true
|
|
110
110
|
},
|
|
111
|
-
"@robono/calling-react-native": {
|
|
112
|
-
"optional": true
|
|
113
|
-
},
|
|
114
111
|
"expo-clipboard": {
|
|
115
112
|
"optional": true
|
|
116
113
|
},
|