@ethora/chat-component-rn 26.10.2 → 26.10.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.
- package/lib/commonjs/components/Header/HeaderRoomList.js +72 -69
- package/lib/commonjs/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatHeader.js +13 -11
- package/lib/commonjs/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MessageContainer.js +10 -2
- package/lib/commonjs/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/commonjs/components/MainComponents/RoomList.js +8 -18
- package/lib/commonjs/components/MainComponents/RoomList.js.map +1 -1
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js +17 -14
- package/lib/commonjs/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js +131 -17
- package/lib/commonjs/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js +6 -1
- package/lib/commonjs/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/ActiveCallBar.js +203 -0
- package/lib/commonjs/components/VideoCalls/ActiveCallBar.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/CallButtons.js +3 -1
- package/lib/commonjs/components/VideoCalls/CallButtons.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js +123 -129
- package/lib/commonjs/components/VideoCalls/VideoCallOverlay.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js +212 -414
- package/lib/commonjs/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/callActions.js +61 -0
- package/lib/commonjs/components/VideoCalls/callActions.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/callSessionController.js +461 -0
- package/lib/commonjs/components/VideoCalls/callSessionController.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/callUiStore.js +91 -0
- package/lib/commonjs/components/VideoCalls/callUiStore.js.map +1 -0
- package/lib/commonjs/components/VideoCalls/livekitRuntime.js +1 -0
- package/lib/commonjs/components/VideoCalls/livekitRuntime.js.map +1 -1
- package/lib/commonjs/components/VideoCalls/useDraggable.js +59 -0
- package/lib/commonjs/components/VideoCalls/useDraggable.js.map +1 -0
- package/lib/commonjs/helpers/createRoomFromApi.js +4 -0
- package/lib/commonjs/helpers/createRoomFromApi.js.map +1 -1
- package/lib/commonjs/helpers/incomingCallFromPush.js +1 -1
- package/lib/commonjs/helpers/incomingCallFromPush.js.map +1 -1
- package/lib/commonjs/helpers/roomUserCount.js +7 -1
- package/lib/commonjs/helpers/roomUserCount.js.map +1 -1
- package/lib/commonjs/helpers/uniqueMembers.js +36 -0
- package/lib/commonjs/helpers/uniqueMembers.js.map +1 -0
- package/lib/commonjs/hooks/useLeaveRoom.js +52 -0
- package/lib/commonjs/hooks/useLeaveRoom.js.map +1 -0
- package/lib/commonjs/i18n/strings.js +24 -0
- package/lib/commonjs/i18n/strings.js.map +1 -1
- package/lib/commonjs/networking/api-requests/rooms.api.js +36 -1
- package/lib/commonjs/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/commonjs/networking/callTokenStanza.js +47 -3
- package/lib/commonjs/networking/callTokenStanza.js.map +1 -1
- package/lib/commonjs/networking/xmppClient.js +9 -2
- package/lib/commonjs/networking/xmppClient.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/module/components/Header/HeaderRoomList.js +73 -70
- package/lib/module/components/Header/HeaderRoomList.js.map +1 -1
- package/lib/module/components/MainComponents/ChatHeader.js +15 -13
- package/lib/module/components/MainComponents/ChatHeader.js.map +1 -1
- package/lib/module/components/MainComponents/MessageContainer.js +10 -2
- package/lib/module/components/MainComponents/MessageContainer.js.map +1 -1
- package/lib/module/components/MainComponents/RoomList.js +8 -18
- package/lib/module/components/MainComponents/RoomList.js.map +1 -1
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js +18 -15
- package/lib/module/components/Modals/ChatProfileModal/ChatProfileModal.js.map +1 -1
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js +132 -18
- package/lib/module/components/Modals/UserProfileModal/UserProfileModal.js.map +1 -1
- package/lib/module/components/RoomComponents/ChatRoomItem.js +6 -1
- package/lib/module/components/RoomComponents/ChatRoomItem.js.map +1 -1
- package/lib/module/components/VideoCalls/ActiveCallBar.js +195 -0
- package/lib/module/components/VideoCalls/ActiveCallBar.js.map +1 -0
- package/lib/module/components/VideoCalls/CallButtons.js +3 -1
- package/lib/module/components/VideoCalls/CallButtons.js.map +1 -1
- package/lib/module/components/VideoCalls/VideoCallOverlay.js +125 -131
- package/lib/module/components/VideoCalls/VideoCallOverlay.js.map +1 -1
- package/lib/module/components/VideoCalls/VideoCallSession.js +213 -417
- package/lib/module/components/VideoCalls/VideoCallSession.js.map +1 -1
- package/lib/module/components/VideoCalls/callActions.js +55 -0
- package/lib/module/components/VideoCalls/callActions.js.map +1 -0
- package/lib/module/components/VideoCalls/callSessionController.js +450 -0
- package/lib/module/components/VideoCalls/callSessionController.js.map +1 -0
- package/lib/module/components/VideoCalls/callUiStore.js +84 -0
- package/lib/module/components/VideoCalls/callUiStore.js.map +1 -0
- package/lib/module/components/VideoCalls/livekitRuntime.js +1 -0
- package/lib/module/components/VideoCalls/livekitRuntime.js.map +1 -1
- package/lib/module/components/VideoCalls/useDraggable.js +55 -0
- package/lib/module/components/VideoCalls/useDraggable.js.map +1 -0
- package/lib/module/helpers/createRoomFromApi.js +4 -0
- package/lib/module/helpers/createRoomFromApi.js.map +1 -1
- package/lib/module/helpers/incomingCallFromPush.js +1 -1
- package/lib/module/helpers/incomingCallFromPush.js.map +1 -1
- package/lib/module/helpers/roomUserCount.js +7 -1
- package/lib/module/helpers/roomUserCount.js.map +1 -1
- package/lib/module/helpers/uniqueMembers.js +31 -0
- package/lib/module/helpers/uniqueMembers.js.map +1 -0
- package/lib/module/hooks/useLeaveRoom.js +48 -0
- package/lib/module/hooks/useLeaveRoom.js.map +1 -0
- package/lib/module/i18n/strings.js +24 -0
- package/lib/module/i18n/strings.js.map +1 -1
- package/lib/module/networking/api-requests/rooms.api.js +35 -1
- package/lib/module/networking/api-requests/rooms.api.js.map +1 -1
- package/lib/module/networking/callTokenStanza.js +47 -3
- package/lib/module/networking/callTokenStanza.js.map +1 -1
- package/lib/module/networking/xmppClient.js +8 -1
- package/lib/module/networking/xmppClient.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/components/Header/HeaderRoomList.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatHeader.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MessageContainer.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/RoomList.d.ts.map +1 -1
- package/lib/typescript/components/Modals/ChatProfileModal/ChatProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/UserProfileModal/UserProfileModal.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/ChatRoomItem.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts +21 -0
- package/lib/typescript/components/VideoCalls/ActiveCallBar.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/CallButtons.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts +0 -6
- package/lib/typescript/components/VideoCalls/VideoCallOverlay.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts +15 -22
- package/lib/typescript/components/VideoCalls/VideoCallSession.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/callActions.d.ts +15 -0
- package/lib/typescript/components/VideoCalls/callActions.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/callSessionController.d.ts +63 -0
- package/lib/typescript/components/VideoCalls/callSessionController.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/callUiStore.d.ts +24 -0
- package/lib/typescript/components/VideoCalls/callUiStore.d.ts.map +1 -0
- package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts +2 -0
- package/lib/typescript/components/VideoCalls/livekitRuntime.d.ts.map +1 -1
- package/lib/typescript/components/VideoCalls/useDraggable.d.ts +19 -0
- package/lib/typescript/components/VideoCalls/useDraggable.d.ts.map +1 -0
- package/lib/typescript/helpers/createRoomFromApi.d.ts.map +1 -1
- package/lib/typescript/helpers/roomUserCount.d.ts +1 -0
- package/lib/typescript/helpers/roomUserCount.d.ts.map +1 -1
- package/lib/typescript/helpers/uniqueMembers.d.ts +11 -0
- package/lib/typescript/helpers/uniqueMembers.d.ts.map +1 -0
- package/lib/typescript/hooks/useLeaveRoom.d.ts +9 -0
- package/lib/typescript/hooks/useLeaveRoom.d.ts.map +1 -0
- package/lib/typescript/i18n/strings.d.ts.map +1 -1
- package/lib/typescript/networking/api-requests/rooms.api.d.ts +8 -0
- package/lib/typescript/networking/api-requests/rooms.api.d.ts.map +1 -1
- package/lib/typescript/networking/callTokenStanza.d.ts.map +1 -1
- package/lib/typescript/networking/xmppClient.d.ts.map +1 -1
- package/lib/typescript/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/Header/HeaderRoomList.tsx +66 -61
- package/src/components/MainComponents/ChatHeader.tsx +13 -8
- package/src/components/MainComponents/MessageContainer.tsx +14 -1
- package/src/components/MainComponents/RoomList.tsx +8 -14
- package/src/components/Modals/ChatProfileModal/ChatProfileModal.tsx +16 -13
- package/src/components/Modals/UserProfileModal/UserProfileModal.tsx +167 -36
- package/src/components/RoomComponents/ChatRoomItem.tsx +8 -1
- package/src/components/VideoCalls/ActiveCallBar.tsx +176 -0
- package/src/components/VideoCalls/CallButtons.tsx +5 -1
- package/src/components/VideoCalls/VideoCallOverlay.tsx +153 -183
- package/src/components/VideoCalls/VideoCallSession.tsx +227 -439
- package/src/components/VideoCalls/callActions.ts +63 -0
- package/src/components/VideoCalls/callSessionController.ts +439 -0
- package/src/components/VideoCalls/callUiStore.ts +76 -0
- package/src/components/VideoCalls/livekitRuntime.ts +3 -0
- package/src/components/VideoCalls/useDraggable.ts +46 -0
- package/src/helpers/createRoomFromApi.tsx +2 -0
- package/src/helpers/incomingCallFromPush.ts +2 -2
- package/src/helpers/roomUserCount.ts +6 -2
- package/src/helpers/uniqueMembers.ts +26 -0
- package/src/hooks/useLeaveRoom.ts +42 -0
- package/src/i18n/strings.ts +24 -0
- package/src/networking/api-requests/rooms.api.ts +28 -1
- package/src/networking/callTokenStanza.ts +46 -6
- package/src/networking/xmppClient.ts +10 -1
- package/src/version.ts +1 -1
|
@@ -3,12 +3,15 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.default = exports.VideoCallSession = void 0;
|
|
6
|
+
exports.useSharedCallElapsed = exports.formatCallDuration = exports.default = exports.VideoCallSession = void 0;
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _reactNative = require("react-native");
|
|
9
|
+
var _reactNativeSafeAreaContext = require("react-native-safe-area-context");
|
|
9
10
|
var _ProfileImagePlaceholder = require("../MainComponents/ProfileImagePlaceholder");
|
|
10
11
|
var _CallIcons = require("./CallIcons");
|
|
11
12
|
var _livekitRuntime = require("./livekitRuntime");
|
|
13
|
+
var _callSessionController = require("./callSessionController");
|
|
14
|
+
var _useDraggable = require("./useDraggable");
|
|
12
15
|
var _useT = require("../../i18n/useT");
|
|
13
16
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
17
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
@@ -18,329 +21,62 @@ const TEXT_ON_DARK = '#FFFFFF';
|
|
|
18
21
|
const TEXT_MUTED = '#9AA4B2';
|
|
19
22
|
const DANGER = '#E53935';
|
|
20
23
|
const CONTROL_IDLE = 'rgba(255, 255, 255, 0.16)';
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (name === 'NotReadableError' || text.includes('in use')) {
|
|
38
|
-
return t('call.error.deviceInUse');
|
|
24
|
+
/**
|
|
25
|
+
* Seconds since the call truly connected, counted from the server-set
|
|
26
|
+
* `joinedAt` anchor so both sides show the same time (web's
|
|
27
|
+
* useSharedCallElapsed). Null until the peer is in.
|
|
28
|
+
*/
|
|
29
|
+
const useSharedCallElapsed = anchorAt => {
|
|
30
|
+
const [, tick] = (0, _react.useState)(0);
|
|
31
|
+
(0, _react.useEffect)(() => {
|
|
32
|
+
if (anchorAt === null) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const id = setInterval(() => tick(n => n + 1), 1000);
|
|
36
|
+
return () => clearInterval(id);
|
|
37
|
+
}, [anchorAt]);
|
|
38
|
+
if (anchorAt === null) {
|
|
39
|
+
return null;
|
|
39
40
|
}
|
|
40
|
-
return
|
|
41
|
+
return Math.max(0, Math.floor((Date.now() - anchorAt) / 1000));
|
|
41
42
|
};
|
|
43
|
+
exports.useSharedCallElapsed = useSharedCallElapsed;
|
|
44
|
+
const formatCallDuration = totalSeconds => {
|
|
45
|
+
const safe = Math.max(0, Math.floor(totalSeconds));
|
|
46
|
+
const hours = Math.floor(safe / 3600);
|
|
47
|
+
const minutes = Math.floor(safe % 3600 / 60);
|
|
48
|
+
const seconds = safe % 60;
|
|
49
|
+
const mm = String(minutes).padStart(2, '0');
|
|
50
|
+
const ss = String(seconds).padStart(2, '0');
|
|
51
|
+
return hours > 0 ? `${hours}:${mm}:${ss}` : `${mm}:${ss}`;
|
|
52
|
+
};
|
|
53
|
+
|
|
42
54
|
/**
|
|
43
|
-
* The
|
|
55
|
+
* The call screen, React Native edition. Pure view over the LiveKit session
|
|
56
|
+
* owned by callSessionController.ts: it can unmount and remount (minimize,
|
|
57
|
+
* leaving the chat screen) without touching the connection.
|
|
44
58
|
*
|
|
45
|
-
* The web SDK builds this on `@livekit/components-react` hooks
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* connection state) in local React state, re-syncing on RoomEvent. Only the
|
|
49
|
-
* actual video surface comes from `@livekit/react-native` (`<VideoTrack />`),
|
|
50
|
-
* which wraps the native renderer.
|
|
51
|
-
*
|
|
52
|
-
* Requires `@livekit/react-native` >= 2.7 for the `trackRef` prop shape used
|
|
53
|
-
* below. Both LiveKit packages are optional peer deps, see livekitRuntime.ts.
|
|
59
|
+
* The web SDK builds this on `@livekit/components-react` hooks, which
|
|
60
|
+
* assume a DOM. Only the video surface comes from `@livekit/react-native`
|
|
61
|
+
* (`<VideoTrack />`, `trackRef` prop, >= 2.7).
|
|
54
62
|
*/
|
|
63
|
+
exports.formatCallDuration = formatCallDuration;
|
|
55
64
|
const VideoCallSession = ({
|
|
56
|
-
token,
|
|
57
|
-
livekitUrl,
|
|
58
65
|
kind = 'video',
|
|
59
66
|
peerName,
|
|
60
67
|
primaryColor = DEFAULT_PRIMARY,
|
|
61
68
|
icons,
|
|
62
|
-
startWithCameraOn = true,
|
|
63
|
-
startWithMicOn = true,
|
|
64
|
-
minimized = false,
|
|
65
69
|
onToggleMinimize,
|
|
66
|
-
onConnected,
|
|
67
|
-
onError,
|
|
68
70
|
onHangup
|
|
69
71
|
}) => {
|
|
70
72
|
const t = (0, _useT.useT)();
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
const [
|
|
78
|
-
const [remoteVideo, setRemoteVideo] = (0, _react.useState)(null);
|
|
79
|
-
const [localVideo, setLocalVideo] = (0, _react.useState)(null);
|
|
80
|
-
const [remoteName, setRemoteName] = (0, _react.useState)(null);
|
|
81
|
-
const [remoteJoined, setRemoteJoined] = (0, _react.useState)(false);
|
|
82
|
-
|
|
83
|
-
// Callbacks are read through a ref inside the connect effect so that a
|
|
84
|
-
// parent re-render (new inline arrow props) never re-runs connect and
|
|
85
|
-
// tears down a live call. Same guard the web session uses.
|
|
86
|
-
const callbacksRef = (0, _react.useRef)({
|
|
87
|
-
onConnected,
|
|
88
|
-
onError,
|
|
89
|
-
onHangup
|
|
90
|
-
});
|
|
91
|
-
(0, _react.useEffect)(() => {
|
|
92
|
-
callbacksRef.current = {
|
|
93
|
-
onConnected,
|
|
94
|
-
onError,
|
|
95
|
-
onHangup
|
|
96
|
-
};
|
|
97
|
-
}, [onConnected, onError, onHangup]);
|
|
98
|
-
|
|
99
|
-
// ---- track plumbing -------------------------------------------------
|
|
100
|
-
|
|
101
|
-
// Build the { participant, publication, source } shape `<VideoTrack />`
|
|
102
|
-
// expects, from whatever camera publication a participant currently has.
|
|
103
|
-
const toTrackRef = (0, _react.useCallback)((participant, Track) => {
|
|
104
|
-
if (!participant) {
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
const publication = participant.getTrackPublication?.(Track.Source.Camera);
|
|
108
|
-
if (!publication?.track) {
|
|
109
|
-
return null;
|
|
110
|
-
}
|
|
111
|
-
return {
|
|
112
|
-
participant,
|
|
113
|
-
publication,
|
|
114
|
-
source: Track.Source.Camera
|
|
115
|
-
};
|
|
116
|
-
}, []);
|
|
117
|
-
const resyncTracks = (0, _react.useCallback)(() => {
|
|
118
|
-
const room = roomRef.current;
|
|
119
|
-
if (!room || !runtime) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
const {
|
|
123
|
-
Track
|
|
124
|
-
} = runtime;
|
|
125
|
-
const remote = Array.from(room.remoteParticipants?.values?.() || [])[0];
|
|
126
|
-
setRemoteJoined(!!remote);
|
|
127
|
-
setRemoteName(remote?.name || remote?.identity || null);
|
|
128
|
-
setRemoteVideo(toTrackRef(remote, Track));
|
|
129
|
-
setLocalVideo(toTrackRef(room.localParticipant, Track));
|
|
130
|
-
}, [runtime, toTrackRef]);
|
|
131
|
-
|
|
132
|
-
// ---- connect / teardown ---------------------------------------------
|
|
133
|
-
|
|
134
|
-
(0, _react.useEffect)(() => {
|
|
135
|
-
if (!runtime) {
|
|
136
|
-
callbacksRef.current.onError?.(t('call.error.sdkMissing'));
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
if (!token || !livekitUrl) {
|
|
140
|
-
callbacksRef.current.onError?.(t('call.error.missingConfig'));
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
(0, _livekitRuntime.ensureLiveKitGlobals)(runtime);
|
|
144
|
-
const {
|
|
145
|
-
Room,
|
|
146
|
-
RoomEvent,
|
|
147
|
-
AudioSession
|
|
148
|
-
} = runtime;
|
|
149
|
-
let disposed = false;
|
|
150
|
-
|
|
151
|
-
// adaptiveStream + dynacast keep mobile data and battery sane: the SDK
|
|
152
|
-
// drops resolution for a small tile and stops publishing layers nobody
|
|
153
|
-
// subscribes to. Both are safe defaults for 1:1.
|
|
154
|
-
const room = new Room({
|
|
155
|
-
adaptiveStream: true,
|
|
156
|
-
dynacast: true
|
|
157
|
-
});
|
|
158
|
-
roomRef.current = room;
|
|
159
|
-
const onStateChange = () => {
|
|
160
|
-
if (disposed) {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
resyncTracks();
|
|
164
|
-
};
|
|
165
|
-
room.on(RoomEvent.TrackSubscribed, onStateChange).on(RoomEvent.TrackUnsubscribed, onStateChange).on(RoomEvent.LocalTrackPublished, onStateChange).on(RoomEvent.LocalTrackUnpublished, onStateChange).on(RoomEvent.TrackMuted, onStateChange).on(RoomEvent.TrackUnmuted, onStateChange).on(RoomEvent.ParticipantConnected, onStateChange).on(RoomEvent.MediaDevicesError, error => {
|
|
166
|
-
if (disposed) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
setDeviceError(humanizeDeviceError(error, t));
|
|
170
|
-
}).on(RoomEvent.ParticipantDisconnected, () => {
|
|
171
|
-
if (disposed) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
resyncTracks();
|
|
175
|
-
// 1:1 semantics: the other side leaving IS the end of the call.
|
|
176
|
-
// Without this the local user sits on a black canvas until they
|
|
177
|
-
// hang up manually.
|
|
178
|
-
callbacksRef.current.onHangup?.();
|
|
179
|
-
}).on(RoomEvent.Disconnected, () => {
|
|
180
|
-
if (disposed) {
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
setConnected(false);
|
|
184
|
-
callbacksRef.current.onHangup?.();
|
|
185
|
-
});
|
|
186
|
-
(async () => {
|
|
187
|
-
// Joining the LiveKit room is the only step whose failure should fail
|
|
188
|
-
// the call (bad token, network, server down). Everything after this
|
|
189
|
-
// is best-effort device setup — see the separate try/catches below.
|
|
190
|
-
try {
|
|
191
|
-
// Claims audio focus and sets the right native audio mode. Must
|
|
192
|
-
// start BEFORE connecting or the first seconds route to the
|
|
193
|
-
// earpiece on Android even for a video call.
|
|
194
|
-
await AudioSession.startAudioSession();
|
|
195
|
-
await room.connect(livekitUrl, token);
|
|
196
|
-
} catch (error) {
|
|
197
|
-
if (disposed) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
callbacksRef.current.onError?.(String(error?.message || '') || t('call.error.connectFailed'));
|
|
201
|
-
return;
|
|
202
|
-
}
|
|
203
|
-
if (disposed) {
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Devices are best-effort: if the mic/camera prompt is blocked, or —
|
|
208
|
-
// notably — this is the iOS Simulator (no real camera hardware at
|
|
209
|
-
// all), the call still connects. The user can hear/be heard on
|
|
210
|
-
// audio and re-enable the camera later; failing the whole call here
|
|
211
|
-
// (as an earlier version did, sharing one try/catch with `connect`)
|
|
212
|
-
// meant every video call died before ever reaching the ring-answered
|
|
213
|
-
// screen — indistinguishable from "Accept doesn't work".
|
|
214
|
-
try {
|
|
215
|
-
await room.localParticipant.setMicrophoneEnabled(startWithMicOn);
|
|
216
|
-
} catch (error) {
|
|
217
|
-
if (!disposed) {
|
|
218
|
-
setDeviceError(humanizeDeviceError(error, t));
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
if (kind === 'video') {
|
|
222
|
-
try {
|
|
223
|
-
await room.localParticipant.setCameraEnabled(startWithCameraOn);
|
|
224
|
-
} catch (error) {
|
|
225
|
-
if (!disposed) {
|
|
226
|
-
setDeviceError(humanizeDeviceError(error, t));
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
if (disposed) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Video calls belong on the loudspeaker, audio calls on the
|
|
235
|
-
// earpiece, matching what every native dialer does.
|
|
236
|
-
try {
|
|
237
|
-
await AudioSession.setAppleAudioConfiguration?.({
|
|
238
|
-
audioCategory: 'playAndRecord',
|
|
239
|
-
audioMode: kind === 'video' ? 'videoChat' : 'voiceChat'
|
|
240
|
-
});
|
|
241
|
-
} catch {
|
|
242
|
-
// iOS-only helper, absent on Android builds of the SDK.
|
|
243
|
-
}
|
|
244
|
-
setConnected(true);
|
|
245
|
-
resyncTracks();
|
|
246
|
-
callbacksRef.current.onConnected?.();
|
|
247
|
-
})();
|
|
248
|
-
return () => {
|
|
249
|
-
disposed = true;
|
|
250
|
-
try {
|
|
251
|
-
room.removeAllListeners?.();
|
|
252
|
-
void room.disconnect();
|
|
253
|
-
} catch {
|
|
254
|
-
// Already gone.
|
|
255
|
-
}
|
|
256
|
-
try {
|
|
257
|
-
void AudioSession.stopAudioSession();
|
|
258
|
-
} catch {
|
|
259
|
-
// Never let teardown throw, it runs during unmount.
|
|
260
|
-
}
|
|
261
|
-
roomRef.current = null;
|
|
262
|
-
};
|
|
263
|
-
// Connect exactly once per (url, token, kind). Everything else is read
|
|
264
|
-
// through refs, see callbacksRef above.
|
|
265
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
266
|
-
}, [runtime, livekitUrl, token, kind]);
|
|
267
|
-
|
|
268
|
-
// ---- controls --------------------------------------------------------
|
|
269
|
-
|
|
270
|
-
const toggleMic = (0, _react.useCallback)(async () => {
|
|
271
|
-
const room = roomRef.current;
|
|
272
|
-
if (!room) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
const next = !micOn;
|
|
276
|
-
setMicOn(next);
|
|
277
|
-
try {
|
|
278
|
-
await room.localParticipant.setMicrophoneEnabled(next);
|
|
279
|
-
} catch {
|
|
280
|
-
setMicOn(!next);
|
|
281
|
-
}
|
|
282
|
-
}, [micOn]);
|
|
283
|
-
const toggleCamera = (0, _react.useCallback)(async () => {
|
|
284
|
-
const room = roomRef.current;
|
|
285
|
-
if (!room) {
|
|
286
|
-
return;
|
|
287
|
-
}
|
|
288
|
-
const next = !cameraOn;
|
|
289
|
-
setCameraOn(next);
|
|
290
|
-
try {
|
|
291
|
-
await room.localParticipant.setCameraEnabled(next);
|
|
292
|
-
resyncTracks();
|
|
293
|
-
} catch {
|
|
294
|
-
setCameraOn(!next);
|
|
295
|
-
}
|
|
296
|
-
}, [cameraOn, resyncTracks]);
|
|
297
|
-
const switchCamera = (0, _react.useCallback)(async () => {
|
|
298
|
-
const room = roomRef.current;
|
|
299
|
-
if (!room || !runtime) {
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
try {
|
|
303
|
-
const publication = room.localParticipant.getTrackPublication?.(runtime.Track.Source.Camera);
|
|
304
|
-
const track = publication?.track;
|
|
305
|
-
// `restartTrack` with the flipped facingMode is the portable way to
|
|
306
|
-
// switch cameras; the RN SDK's `_switchCamera` helper is internal and
|
|
307
|
-
// has moved between versions.
|
|
308
|
-
await track?.restartTrack?.({
|
|
309
|
-
facingMode: track?.mediaStreamTrack?.getSettings?.().facingMode === 'environment' ? 'user' : 'environment'
|
|
310
|
-
});
|
|
311
|
-
resyncTracks();
|
|
312
|
-
} catch {
|
|
313
|
-
// Device has a single camera, or the track is mid-restart.
|
|
314
|
-
}
|
|
315
|
-
}, [runtime, resyncTracks]);
|
|
316
|
-
const toggleSpeaker = (0, _react.useCallback)(async () => {
|
|
317
|
-
const next = !speakerOn;
|
|
318
|
-
setSpeakerOn(next);
|
|
319
|
-
if (!runtime) {
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
try {
|
|
323
|
-
if (_reactNative.Platform.OS === 'android') {
|
|
324
|
-
// NB: not `setAndroidAudioConfiguration` — that method has never
|
|
325
|
-
// existed on AudioSession (the old `?.` call silently no-oped, so
|
|
326
|
-
// the speaker icon toggled while audio stayed on the earpiece).
|
|
327
|
-
// `selectAudioOutput` routes directly; on Android its device ids
|
|
328
|
-
// are the literal strings 'speaker' / 'earpiece'.
|
|
329
|
-
await runtime.AudioSession.selectAudioOutput(next ? 'speaker' : 'earpiece');
|
|
330
|
-
} else {
|
|
331
|
-
await runtime.AudioSession.setAppleAudioConfiguration?.({
|
|
332
|
-
audioCategory: 'playAndRecord',
|
|
333
|
-
audioCategoryOptions: next ? ['defaultToSpeaker'] : [],
|
|
334
|
-
audioMode: next ? 'videoChat' : 'voiceChat'
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
} catch {
|
|
338
|
-
setSpeakerOn(!next);
|
|
339
|
-
}
|
|
340
|
-
}, [runtime, speakerOn]);
|
|
341
|
-
|
|
342
|
-
// ---- render ----------------------------------------------------------
|
|
343
|
-
|
|
73
|
+
const insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
|
|
74
|
+
const runtime = (0, _livekitRuntime.loadLiveKit)();
|
|
75
|
+
const session = (0, _callSessionController.useCallSession)();
|
|
76
|
+
const selfView = (0, _useDraggable.useDraggable)();
|
|
77
|
+
const elapsed = useSharedCallElapsed(session.anchorAt);
|
|
78
|
+
// Telegram-style: tap the small tile to swap it with the big one.
|
|
79
|
+
const [swapped, setSwapped] = (0, _react.useState)(false);
|
|
344
80
|
if (!runtime) {
|
|
345
81
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
346
82
|
style: [styles.canvas, styles.centered],
|
|
@@ -353,64 +89,46 @@ const VideoCallSession = ({
|
|
|
353
89
|
const {
|
|
354
90
|
VideoTrack
|
|
355
91
|
} = runtime;
|
|
356
|
-
const
|
|
92
|
+
const {
|
|
93
|
+
connected,
|
|
94
|
+
remoteJoined,
|
|
95
|
+
remoteVideo,
|
|
96
|
+
localVideo,
|
|
97
|
+
micOn,
|
|
98
|
+
cameraOn,
|
|
99
|
+
speakerOn,
|
|
100
|
+
deviceError,
|
|
101
|
+
remoteMicMuted,
|
|
102
|
+
facingMode
|
|
103
|
+
} = session;
|
|
104
|
+
// The call slice's name (the chat title) first, as web does: LiveKit's
|
|
105
|
+
// participant name is often just the opaque xmpp identity.
|
|
106
|
+
const displayName = peerName || session.remoteName || t('call.unknownCaller');
|
|
357
107
|
const isVideo = kind === 'video';
|
|
358
108
|
const showRemoteVideo = isVideo && !!remoteVideo;
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
373
|
-
accessibilityRole: "button",
|
|
374
|
-
accessibilityLabel: t('call.action.expand'),
|
|
375
|
-
onPress: onToggleMinimize,
|
|
376
|
-
style: [styles.miniButton, {
|
|
377
|
-
backgroundColor: CONTROL_IDLE
|
|
378
|
-
}],
|
|
379
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CallIcons.ExpandIcon, {
|
|
380
|
-
color: TEXT_ON_DARK,
|
|
381
|
-
size: 20
|
|
382
|
-
})
|
|
383
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
384
|
-
accessibilityRole: "button",
|
|
385
|
-
accessibilityLabel: t('call.action.hangUp'),
|
|
386
|
-
onPress: onHangup,
|
|
387
|
-
style: [styles.miniButton, {
|
|
388
|
-
backgroundColor: DANGER
|
|
389
|
-
}],
|
|
390
|
-
children: icons?.hangup ?? /*#__PURE__*/(0, _jsxRuntime.jsx)(_CallIcons.HangUpIcon, {
|
|
391
|
-
color: TEXT_ON_DARK,
|
|
392
|
-
size: 20
|
|
393
|
-
})
|
|
394
|
-
})]
|
|
395
|
-
});
|
|
396
|
-
}
|
|
109
|
+
const localLive = isVideo && cameraOn && !!localVideo;
|
|
110
|
+
// Swapping only means something while both sides have a picture; if
|
|
111
|
+
// either goes away, fall back to the default layout on its own.
|
|
112
|
+
const canSwap = showRemoteVideo && localLive;
|
|
113
|
+
const isSwapped = swapped && canSwap;
|
|
114
|
+
const mainVideo = isSwapped ? localVideo : showRemoteVideo ? remoteVideo : null;
|
|
115
|
+
const pipVideo = isSwapped ? remoteVideo : localLive ? localVideo : null;
|
|
116
|
+
// Only the front camera is mirrored, as in every camera app.
|
|
117
|
+
const selfMirror = facingMode === 'user';
|
|
118
|
+
const statusText = elapsed !== null ? formatCallDuration(elapsed) : !connected ? t('call.status.connecting') : !remoteJoined ? t('call.status.waitingForPeer') : t('call.status.inCall');
|
|
119
|
+
const peerMutedLabel = t('call.peerMuted', {
|
|
120
|
+
name: displayName
|
|
121
|
+
});
|
|
397
122
|
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
398
123
|
style: styles.canvas,
|
|
399
|
-
children: [
|
|
400
|
-
style: styles.deviceErrorBanner,
|
|
401
|
-
onPress: () => setDeviceError(null),
|
|
402
|
-
accessibilityRole: "button",
|
|
403
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
404
|
-
style: styles.deviceErrorText,
|
|
405
|
-
numberOfLines: 2,
|
|
406
|
-
children: deviceError
|
|
407
|
-
})
|
|
408
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
124
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
409
125
|
style: styles.stage,
|
|
410
|
-
children: [
|
|
411
|
-
trackRef:
|
|
126
|
+
children: [mainVideo ? /*#__PURE__*/(0, _jsxRuntime.jsx)(VideoTrack, {
|
|
127
|
+
trackRef: mainVideo,
|
|
412
128
|
style: styles.remoteVideo,
|
|
413
|
-
objectFit: "cover"
|
|
129
|
+
objectFit: "cover",
|
|
130
|
+
mirror: isSwapped && selfMirror,
|
|
131
|
+
zOrder: 0
|
|
414
132
|
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
415
133
|
style: styles.centered,
|
|
416
134
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ProfileImagePlaceholder.ProfileImagePlaceholder, {
|
|
@@ -421,36 +139,95 @@ const VideoCallSession = ({
|
|
|
421
139
|
children: displayName
|
|
422
140
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
423
141
|
style: styles.stageStatus,
|
|
424
|
-
children:
|
|
142
|
+
children: isVideo && remoteJoined && elapsed !== null ? t('call.status.cameraOff') : statusText
|
|
425
143
|
}), !connected && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ActivityIndicator, {
|
|
426
144
|
color: primaryColor,
|
|
427
145
|
style: styles.spinner,
|
|
428
146
|
size: "small"
|
|
147
|
+
}), !micOn && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
148
|
+
style: [styles.pill, styles.pillDanger],
|
|
149
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
150
|
+
style: styles.pillDangerText,
|
|
151
|
+
children: t('call.selfMuted')
|
|
152
|
+
})
|
|
153
|
+
}), remoteMicMuted && !showRemoteVideo && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
154
|
+
style: styles.pill,
|
|
155
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
156
|
+
style: styles.pillText,
|
|
157
|
+
children: peerMutedLabel
|
|
158
|
+
})
|
|
159
|
+
})]
|
|
160
|
+
}), mainVideo && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
161
|
+
style: [styles.header, {
|
|
162
|
+
paddingTop: 14 + insets.top
|
|
163
|
+
}],
|
|
164
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
165
|
+
style: styles.headerName,
|
|
166
|
+
numberOfLines: 1,
|
|
167
|
+
children: displayName
|
|
168
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
169
|
+
style: styles.headerStatus,
|
|
170
|
+
children: statusText
|
|
171
|
+
}), remoteMicMuted && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
172
|
+
style: [styles.pill, styles.headerPill],
|
|
173
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_CallIcons.MicOffIcon, {
|
|
174
|
+
color: TEXT_ON_DARK,
|
|
175
|
+
size: 14
|
|
176
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
177
|
+
style: styles.pillText,
|
|
178
|
+
children: peerMutedLabel
|
|
179
|
+
})]
|
|
429
180
|
})]
|
|
430
|
-
}),
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
181
|
+
}), pipVideo && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Animated.View, {
|
|
182
|
+
...selfView.panHandlers,
|
|
183
|
+
style: [styles.pip, {
|
|
184
|
+
top: 16 + insets.top
|
|
185
|
+
}, selfView.style],
|
|
186
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
434
187
|
style: styles.pipVideo,
|
|
435
|
-
|
|
436
|
-
|
|
188
|
+
disabled: !canSwap,
|
|
189
|
+
onPress: () => setSwapped(value => !value),
|
|
190
|
+
accessibilityRole: "button",
|
|
191
|
+
accessibilityLabel: t('call.action.swapVideo'),
|
|
192
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(VideoTrack, {
|
|
193
|
+
trackRef: pipVideo,
|
|
194
|
+
style: styles.pipVideo,
|
|
195
|
+
objectFit: "cover",
|
|
196
|
+
mirror: !isSwapped && selfMirror,
|
|
197
|
+
zOrder: 1
|
|
198
|
+
})
|
|
437
199
|
})
|
|
438
200
|
}), onToggleMinimize && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
439
201
|
accessibilityRole: "button",
|
|
440
202
|
accessibilityLabel: t('call.action.minimize'),
|
|
441
203
|
onPress: onToggleMinimize,
|
|
442
|
-
style: styles.minimizeButton,
|
|
204
|
+
style: [styles.minimizeButton, {
|
|
205
|
+
top: 16 + insets.top
|
|
206
|
+
}],
|
|
443
207
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_CallIcons.MinimizeIcon, {
|
|
444
208
|
color: TEXT_ON_DARK,
|
|
445
209
|
size: 20
|
|
446
210
|
})
|
|
211
|
+
}), !!deviceError && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
212
|
+
style: [styles.deviceErrorBanner, {
|
|
213
|
+
top: 64 + insets.top
|
|
214
|
+
}],
|
|
215
|
+
onPress: _callSessionController.dismissCallDeviceError,
|
|
216
|
+
accessibilityRole: "button",
|
|
217
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
218
|
+
style: styles.deviceErrorText,
|
|
219
|
+
numberOfLines: 2,
|
|
220
|
+
children: deviceError
|
|
221
|
+
})
|
|
447
222
|
})]
|
|
448
223
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
449
|
-
style: styles.controls,
|
|
224
|
+
style: [styles.controls, {
|
|
225
|
+
paddingBottom: 20 + insets.bottom
|
|
226
|
+
}],
|
|
450
227
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
451
228
|
accessibilityRole: "button",
|
|
452
229
|
accessibilityLabel: micOn ? t('call.action.muteMic') : t('call.action.unmuteMic'),
|
|
453
|
-
onPress:
|
|
230
|
+
onPress: _callSessionController.toggleCallMic,
|
|
454
231
|
style: [styles.controlButton, {
|
|
455
232
|
backgroundColor: micOn ? CONTROL_IDLE : DANGER
|
|
456
233
|
}],
|
|
@@ -462,7 +239,7 @@ const VideoCallSession = ({
|
|
|
462
239
|
}), isVideo && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
463
240
|
accessibilityRole: "button",
|
|
464
241
|
accessibilityLabel: cameraOn ? t('call.action.stopCamera') : t('call.action.startCamera'),
|
|
465
|
-
onPress:
|
|
242
|
+
onPress: _callSessionController.toggleCallCamera,
|
|
466
243
|
style: [styles.controlButton, {
|
|
467
244
|
backgroundColor: cameraOn ? CONTROL_IDLE : DANGER
|
|
468
245
|
}],
|
|
@@ -474,7 +251,7 @@ const VideoCallSession = ({
|
|
|
474
251
|
}), isVideo && cameraOn && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
475
252
|
accessibilityRole: "button",
|
|
476
253
|
accessibilityLabel: t('call.action.switchCamera'),
|
|
477
|
-
onPress:
|
|
254
|
+
onPress: _callSessionController.switchCallCamera,
|
|
478
255
|
style: [styles.controlButton, {
|
|
479
256
|
backgroundColor: CONTROL_IDLE
|
|
480
257
|
}],
|
|
@@ -484,7 +261,7 @@ const VideoCallSession = ({
|
|
|
484
261
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
485
262
|
accessibilityRole: "button",
|
|
486
263
|
accessibilityLabel: speakerOn ? t('call.action.speakerOff') : t('call.action.speakerOn'),
|
|
487
|
-
onPress:
|
|
264
|
+
onPress: _callSessionController.toggleCallSpeaker,
|
|
488
265
|
style: [styles.controlButton, {
|
|
489
266
|
backgroundColor: CONTROL_IDLE
|
|
490
267
|
}],
|
|
@@ -515,7 +292,8 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
515
292
|
flex: 1,
|
|
516
293
|
alignItems: 'center',
|
|
517
294
|
justifyContent: 'center',
|
|
518
|
-
gap: 12
|
|
295
|
+
gap: 12,
|
|
296
|
+
paddingHorizontal: 24
|
|
519
297
|
},
|
|
520
298
|
stage: {
|
|
521
299
|
flex: 1,
|
|
@@ -529,26 +307,75 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
529
307
|
stageName: {
|
|
530
308
|
color: TEXT_ON_DARK,
|
|
531
309
|
fontSize: 22,
|
|
532
|
-
marginTop: 16
|
|
310
|
+
marginTop: 16,
|
|
311
|
+
textAlign: 'center'
|
|
533
312
|
},
|
|
534
313
|
stageStatus: {
|
|
535
314
|
color: TEXT_MUTED,
|
|
536
|
-
fontSize: 14
|
|
315
|
+
fontSize: 14,
|
|
316
|
+
fontVariant: ['tabular-nums']
|
|
537
317
|
},
|
|
538
318
|
spinner: {
|
|
539
319
|
marginTop: 8
|
|
540
320
|
},
|
|
321
|
+
header: {
|
|
322
|
+
position: 'absolute',
|
|
323
|
+
top: 0,
|
|
324
|
+
left: 0,
|
|
325
|
+
right: 0,
|
|
326
|
+
paddingHorizontal: 64,
|
|
327
|
+
paddingBottom: 14,
|
|
328
|
+
alignItems: 'center',
|
|
329
|
+
backgroundColor: 'rgba(0,0,0,0.35)',
|
|
330
|
+
gap: 2
|
|
331
|
+
},
|
|
332
|
+
headerName: {
|
|
333
|
+
color: TEXT_ON_DARK,
|
|
334
|
+
fontSize: 15,
|
|
335
|
+
fontWeight: '600'
|
|
336
|
+
},
|
|
337
|
+
headerStatus: {
|
|
338
|
+
color: 'rgba(255,255,255,0.7)',
|
|
339
|
+
fontSize: 13,
|
|
340
|
+
fontVariant: ['tabular-nums']
|
|
341
|
+
},
|
|
342
|
+
headerPill: {
|
|
343
|
+
marginTop: 4,
|
|
344
|
+
backgroundColor: 'rgba(0,0,0,0.45)'
|
|
345
|
+
},
|
|
346
|
+
pill: {
|
|
347
|
+
flexDirection: 'row',
|
|
348
|
+
alignItems: 'center',
|
|
349
|
+
gap: 6,
|
|
350
|
+
paddingVertical: 4,
|
|
351
|
+
paddingHorizontal: 10,
|
|
352
|
+
borderRadius: 999,
|
|
353
|
+
backgroundColor: CONTROL_IDLE
|
|
354
|
+
},
|
|
355
|
+
pillText: {
|
|
356
|
+
color: TEXT_ON_DARK,
|
|
357
|
+
fontSize: 12
|
|
358
|
+
},
|
|
359
|
+
pillDanger: {
|
|
360
|
+
backgroundColor: 'rgba(229, 57, 53, 0.18)',
|
|
361
|
+
borderWidth: 1,
|
|
362
|
+
borderColor: 'rgba(229, 57, 53, 0.45)'
|
|
363
|
+
},
|
|
364
|
+
pillDangerText: {
|
|
365
|
+
color: '#FF8A80',
|
|
366
|
+
fontSize: 12
|
|
367
|
+
},
|
|
541
368
|
pip: {
|
|
542
369
|
position: 'absolute',
|
|
543
370
|
right: 16,
|
|
544
|
-
top: 16,
|
|
545
371
|
width: 104,
|
|
546
372
|
height: 148,
|
|
547
373
|
borderRadius: 12,
|
|
548
374
|
overflow: 'hidden',
|
|
549
375
|
backgroundColor: '#000',
|
|
550
376
|
borderWidth: 1,
|
|
551
|
-
borderColor: 'rgba(255,255,255,0.18)'
|
|
377
|
+
borderColor: 'rgba(255,255,255,0.18)',
|
|
378
|
+
zIndex: 5
|
|
552
379
|
},
|
|
553
380
|
pipVideo: {
|
|
554
381
|
flex: 1
|
|
@@ -556,20 +383,20 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
556
383
|
minimizeButton: {
|
|
557
384
|
position: 'absolute',
|
|
558
385
|
left: 16,
|
|
559
|
-
top: 16,
|
|
560
386
|
width: 36,
|
|
561
387
|
height: 36,
|
|
562
388
|
borderRadius: 18,
|
|
563
389
|
alignItems: 'center',
|
|
564
390
|
justifyContent: 'center',
|
|
565
|
-
backgroundColor: 'rgba(0,0,0,0.45)'
|
|
391
|
+
backgroundColor: 'rgba(0,0,0,0.45)',
|
|
392
|
+
zIndex: 6
|
|
566
393
|
},
|
|
567
394
|
controls: {
|
|
568
395
|
flexDirection: 'row',
|
|
569
396
|
alignItems: 'center',
|
|
570
397
|
justifyContent: 'center',
|
|
571
398
|
gap: 16,
|
|
572
|
-
|
|
399
|
+
paddingTop: 20,
|
|
573
400
|
paddingHorizontal: 16
|
|
574
401
|
},
|
|
575
402
|
controlButton: {
|
|
@@ -588,11 +415,10 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
588
415
|
textAlign: 'center',
|
|
589
416
|
paddingHorizontal: 24
|
|
590
417
|
},
|
|
591
|
-
// Dismissible, non-blocking
|
|
592
|
-
//
|
|
418
|
+
// Dismissible, non-blocking: the call is still up underneath; this only
|
|
419
|
+
// flags that camera/mic didn't come up.
|
|
593
420
|
deviceErrorBanner: {
|
|
594
421
|
position: 'absolute',
|
|
595
|
-
top: 16,
|
|
596
422
|
left: 16,
|
|
597
423
|
right: 16,
|
|
598
424
|
zIndex: 10,
|
|
@@ -605,34 +431,6 @@ const styles = _reactNative.StyleSheet.create({
|
|
|
605
431
|
color: TEXT_ON_DARK,
|
|
606
432
|
fontSize: 13,
|
|
607
433
|
textAlign: 'center'
|
|
608
|
-
},
|
|
609
|
-
miniBar: {
|
|
610
|
-
flexDirection: 'row',
|
|
611
|
-
alignItems: 'center',
|
|
612
|
-
gap: 12,
|
|
613
|
-
paddingHorizontal: 16,
|
|
614
|
-
paddingVertical: 12,
|
|
615
|
-
borderRadius: 16,
|
|
616
|
-
backgroundColor: SURFACE_DARK
|
|
617
|
-
},
|
|
618
|
-
miniInfo: {
|
|
619
|
-
flex: 1,
|
|
620
|
-
minWidth: 0
|
|
621
|
-
},
|
|
622
|
-
miniName: {
|
|
623
|
-
color: TEXT_ON_DARK,
|
|
624
|
-
fontSize: 15
|
|
625
|
-
},
|
|
626
|
-
miniStatus: {
|
|
627
|
-
color: TEXT_MUTED,
|
|
628
|
-
fontSize: 12
|
|
629
|
-
},
|
|
630
|
-
miniButton: {
|
|
631
|
-
width: 40,
|
|
632
|
-
height: 40,
|
|
633
|
-
borderRadius: 20,
|
|
634
|
-
alignItems: 'center',
|
|
635
|
-
justifyContent: 'center'
|
|
636
434
|
}
|
|
637
435
|
});
|
|
638
436
|
var _default = exports.default = VideoCallSession;
|