@ethora/chat-component-rn 26.5.11 → 26.5.12
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 +6 -0
- package/README.md +1 -0
- package/lib/commonjs/assets/icons.js +7 -1
- package/lib/commonjs/assets/icons.js.map +1 -1
- package/lib/commonjs/components/MainComponents/ChatRoom.js +17 -1
- package/lib/commonjs/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/commonjs/components/MainComponents/MediaMessage.js +288 -5
- package/lib/commonjs/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js +23 -3
- package/lib/commonjs/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/DocumentViewer.js +5 -44
- package/lib/commonjs/components/Modals/FilePreviewModal/DocumentViewer.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js +36 -3
- package/lib/commonjs/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/commonjs/components/Modals/FilePreviewModal/GViewWebView.js +149 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/GViewWebView.js.map +1 -0
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js +4 -17
- package/lib/commonjs/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js +19 -33
- package/lib/commonjs/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
- package/lib/commonjs/components/styled/AudioMessage.js +643 -66
- package/lib/commonjs/components/styled/AudioMessage.js.map +1 -1
- package/lib/commonjs/components/styled/Button.js +9 -3
- package/lib/commonjs/components/styled/Button.js.map +1 -1
- package/lib/commonjs/components/styled/SendInput.js +239 -40
- package/lib/commonjs/components/styled/SendInput.js.map +1 -1
- package/lib/commonjs/components/styled/StyledInputComponents/MediaComponents.js +31 -18
- package/lib/commonjs/components/styled/StyledInputComponents/MediaComponents.js.map +1 -1
- package/lib/commonjs/components/styled/UnsupportedType.js +47 -5
- package/lib/commonjs/components/styled/UnsupportedType.js.map +1 -1
- package/lib/commonjs/context/xmppProvider.js +5 -2
- package/lib/commonjs/context/xmppProvider.js.map +1 -1
- package/lib/commonjs/helpers/keyboardLayout.js +5 -3
- package/lib/commonjs/helpers/keyboardLayout.js.map +1 -1
- package/lib/commonjs/helpers/mimeToExtension.js +70 -3
- package/lib/commonjs/helpers/mimeToExtension.js.map +1 -1
- package/lib/commonjs/hooks/useEventHandlers.js +1 -1
- package/lib/commonjs/hooks/useEventHandlers.js.map +1 -1
- package/lib/commonjs/hooks/useSendMessage.js +6 -3
- package/lib/commonjs/hooks/useSendMessage.js.map +1 -1
- package/lib/commonjs/roomStore/roomsSlice.js +6 -0
- package/lib/commonjs/roomStore/roomsSlice.js.map +1 -1
- package/lib/module/assets/icons.js +7 -1
- package/lib/module/assets/icons.js.map +1 -1
- package/lib/module/components/MainComponents/ChatRoom.js +18 -2
- package/lib/module/components/MainComponents/ChatRoom.js.map +1 -1
- package/lib/module/components/MainComponents/MediaMessage.js +290 -7
- package/lib/module/components/MainComponents/MediaMessage.js.map +1 -1
- package/lib/module/components/MessageBubble/MessageInteractions.js +24 -4
- package/lib/module/components/MessageBubble/MessageInteractions.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/DocumentViewer.js +5 -45
- package/lib/module/components/Modals/FilePreviewModal/DocumentViewer.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js +36 -3
- package/lib/module/components/Modals/FilePreviewModal/FilePreviewModal.js.map +1 -1
- package/lib/module/components/Modals/FilePreviewModal/GViewWebView.js +144 -0
- package/lib/module/components/Modals/FilePreviewModal/GViewWebView.js.map +1 -0
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js +3 -17
- package/lib/module/components/Modals/FilePreviewModal/PdfView.js.map +1 -1
- package/lib/module/components/RoomComponents/styled/LastAudioMessage.js +20 -34
- package/lib/module/components/RoomComponents/styled/LastAudioMessage.js.map +1 -1
- package/lib/module/components/styled/AudioMessage.js +644 -67
- package/lib/module/components/styled/AudioMessage.js.map +1 -1
- package/lib/module/components/styled/Button.js +9 -3
- package/lib/module/components/styled/Button.js.map +1 -1
- package/lib/module/components/styled/SendInput.js +240 -42
- package/lib/module/components/styled/SendInput.js.map +1 -1
- package/lib/module/components/styled/StyledInputComponents/MediaComponents.js +31 -18
- package/lib/module/components/styled/StyledInputComponents/MediaComponents.js.map +1 -1
- package/lib/module/components/styled/UnsupportedType.js +47 -5
- package/lib/module/components/styled/UnsupportedType.js.map +1 -1
- package/lib/module/context/xmppProvider.js +5 -2
- package/lib/module/context/xmppProvider.js.map +1 -1
- package/lib/module/helpers/keyboardLayout.js +4 -2
- package/lib/module/helpers/keyboardLayout.js.map +1 -1
- package/lib/module/helpers/mimeToExtension.js +67 -3
- package/lib/module/helpers/mimeToExtension.js.map +1 -1
- package/lib/module/hooks/useEventHandlers.js +1 -1
- package/lib/module/hooks/useEventHandlers.js.map +1 -1
- package/lib/module/hooks/useSendMessage.js +6 -3
- package/lib/module/hooks/useSendMessage.js.map +1 -1
- package/lib/module/roomStore/roomsSlice.js +6 -0
- package/lib/module/roomStore/roomsSlice.js.map +1 -1
- package/lib/typescript/assets/icons.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/ChatRoom.d.ts.map +1 -1
- package/lib/typescript/components/MainComponents/MediaMessage.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble/MessageInteractions.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/DocumentViewer.d.ts +0 -7
- package/lib/typescript/components/Modals/FilePreviewModal/DocumentViewer.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/FilePreviewModal.d.ts.map +1 -1
- package/lib/typescript/components/Modals/FilePreviewModal/GViewWebView.d.ts +8 -0
- package/lib/typescript/components/Modals/FilePreviewModal/GViewWebView.d.ts.map +1 -0
- package/lib/typescript/components/Modals/FilePreviewModal/PdfView.d.ts.map +1 -1
- package/lib/typescript/components/RoomComponents/styled/LastAudioMessage.d.ts.map +1 -1
- package/lib/typescript/components/styled/AudioMessage.d.ts +8 -2
- package/lib/typescript/components/styled/AudioMessage.d.ts.map +1 -1
- package/lib/typescript/components/styled/Button.d.ts.map +1 -1
- package/lib/typescript/components/styled/SendInput.d.ts.map +1 -1
- package/lib/typescript/components/styled/StyledInputComponents/MediaComponents.d.ts +5 -1
- package/lib/typescript/components/styled/StyledInputComponents/MediaComponents.d.ts.map +1 -1
- package/lib/typescript/components/styled/UnsupportedType.d.ts +5 -0
- package/lib/typescript/components/styled/UnsupportedType.d.ts.map +1 -1
- package/lib/typescript/context/xmppProvider.d.ts.map +1 -1
- package/lib/typescript/helpers/keyboardLayout.d.ts +3 -1
- package/lib/typescript/helpers/keyboardLayout.d.ts.map +1 -1
- package/lib/typescript/helpers/mimeToExtension.d.ts +31 -1
- package/lib/typescript/helpers/mimeToExtension.d.ts.map +1 -1
- package/lib/typescript/hooks/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/roomStore/roomsSlice.d.ts.map +1 -1
- package/lib/typescript/types/models/modal.model.d.ts +3 -0
- package/lib/typescript/types/models/modal.model.d.ts.map +1 -1
- package/lib/typescript/types/types.d.ts +13 -0
- package/lib/typescript/types/types.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/assets/icons.tsx +30 -25
- package/src/components/MainComponents/ChatRoom.tsx +21 -0
- package/src/components/MainComponents/MediaMessage.tsx +295 -5
- package/src/components/MessageBubble/MessageInteractions.tsx +35 -3
- package/src/components/Modals/FilePreviewModal/DocumentViewer.tsx +3 -40
- package/src/components/Modals/FilePreviewModal/FilePreviewModal.tsx +39 -3
- package/src/components/Modals/FilePreviewModal/GViewWebView.tsx +142 -0
- package/src/components/Modals/FilePreviewModal/PdfView.tsx +2 -18
- package/src/components/RoomComponents/styled/LastAudioMessage.tsx +20 -35
- package/src/components/styled/AudioMessage.tsx +724 -59
- package/src/components/styled/Button.tsx +20 -11
- package/src/components/styled/SendInput.tsx +255 -46
- package/src/components/styled/StyledInputComponents/MediaComponents.tsx +29 -18
- package/src/components/styled/UnsupportedType.tsx +60 -6
- package/src/context/xmppProvider.tsx +6 -2
- package/src/helpers/keyboardLayout.ts +5 -1
- package/src/helpers/mimeToExtension.ts +116 -2
- package/src/hooks/useEventHandlers.tsx +1 -1
- package/src/hooks/useSendMessage.tsx +12 -6
- package/src/roomStore/roomsSlice.ts +7 -0
- package/src/types/models/modal.model.ts +3 -0
- package/src/types/types.ts +13 -0
|
@@ -75,10 +75,21 @@ const AUDIO_EXTENSIONS = [
|
|
|
75
75
|
'.mp3', '.m4a', '.wav', '.aac', '.ogg', '.flac',
|
|
76
76
|
'.weba', '.webm', '.opus', '.amr', '.3gp', '.3gpp',
|
|
77
77
|
] as const;
|
|
78
|
+
const IOS_AUDIO_PLAYBACK_EXTENSIONS = [
|
|
79
|
+
'.mp3', '.m4a', '.mp4', '.wav', '.aac', '.caf',
|
|
80
|
+
'.aif', '.aiff', '.amr', '.3gp', '.3gpp',
|
|
81
|
+
] as const;
|
|
82
|
+
const IOS_AUDIO_UNSUPPORTED_EXTENSIONS = [
|
|
83
|
+
'.webm', '.weba', '.opus', '.ogg',
|
|
84
|
+
] as const;
|
|
78
85
|
const AUDIO_EXT_RE = new RegExp(
|
|
79
86
|
`(${AUDIO_EXTENSIONS.map((e) => e.replace('.', '\\.')).join('|')})$`,
|
|
80
87
|
'i'
|
|
81
88
|
);
|
|
89
|
+
const IOS_AUDIO_PLAYBACK_EXT_RE = new RegExp(
|
|
90
|
+
`(${IOS_AUDIO_PLAYBACK_EXTENSIONS.map((e) => e.replace('.', '\\.')).join('|')})$`,
|
|
91
|
+
'i'
|
|
92
|
+
);
|
|
82
93
|
// Filename / URL substrings that strongly indicate a voice / audio
|
|
83
94
|
// payload even without an explicit audio extension — e.g. a web-app
|
|
84
95
|
// voicemail uploaded as application/octet-stream named "voicemail-…".
|
|
@@ -95,16 +106,36 @@ const AUDIO_NAME_HINT_RE =
|
|
|
95
106
|
export function isLikelyAudio(
|
|
96
107
|
mime: string | undefined | null,
|
|
97
108
|
fileName?: string | null,
|
|
98
|
-
url?: string | null
|
|
109
|
+
url?: string | null,
|
|
110
|
+
opts?: {
|
|
111
|
+
duration?: number | string | null;
|
|
112
|
+
waveForm?: string | null;
|
|
113
|
+
originalName?: string | null;
|
|
114
|
+
}
|
|
99
115
|
): boolean {
|
|
100
116
|
const m = (mime || '').toLowerCase();
|
|
101
117
|
if (m.startsWith('audio/')) {return true;}
|
|
118
|
+
const durationNum =
|
|
119
|
+
typeof opts?.duration === 'string'
|
|
120
|
+
? Number(opts.duration)
|
|
121
|
+
: opts?.duration ?? 0;
|
|
122
|
+
if (Number.isFinite(durationNum) && durationNum > 0) {return true;}
|
|
123
|
+
if (typeof opts?.waveForm === 'string' && opts.waveForm.trim().length > 0) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
102
126
|
// For octet-stream (and any other non-audio mime) fall through to the
|
|
103
127
|
// filename / URL heuristics. We don't restrict to octet-stream — some
|
|
104
128
|
// backends send no mime at all, or send text/plain by accident.
|
|
105
129
|
const name = (fileName || '').toLowerCase();
|
|
130
|
+
const originalName = (opts?.originalName || '').toLowerCase();
|
|
106
131
|
const urlLast = filenameFromUrl(url).toLowerCase();
|
|
107
|
-
if (
|
|
132
|
+
if (
|
|
133
|
+
AUDIO_EXT_RE.test(name) ||
|
|
134
|
+
AUDIO_EXT_RE.test(originalName) ||
|
|
135
|
+
AUDIO_EXT_RE.test(urlLast)
|
|
136
|
+
) {
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
108
139
|
// Last resort: voice-message naming hint anywhere in the filename, the
|
|
109
140
|
// URL's last segment, OR the URL's full path. Voicemails are commonly
|
|
110
141
|
// hosted under `/voice/abc-123` or `/voicemail/abc-123` where the last
|
|
@@ -120,6 +151,7 @@ export function isLikelyAudio(
|
|
|
120
151
|
})();
|
|
121
152
|
if (
|
|
122
153
|
AUDIO_NAME_HINT_RE.test(name) ||
|
|
154
|
+
AUDIO_NAME_HINT_RE.test(originalName) ||
|
|
123
155
|
AUDIO_NAME_HINT_RE.test(urlLast) ||
|
|
124
156
|
AUDIO_NAME_HINT_RE.test(urlPath)
|
|
125
157
|
) {
|
|
@@ -156,6 +188,88 @@ export function filenameFromUrl(url: string | undefined | null): string {
|
|
|
156
188
|
}
|
|
157
189
|
}
|
|
158
190
|
|
|
191
|
+
const getLowerExtension = (value: string | undefined | null) => {
|
|
192
|
+
if (!value) {return '';}
|
|
193
|
+
const match = value.toLowerCase().match(VALID_EXT_RE);
|
|
194
|
+
return match ? match[0] : '';
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* AVFoundation on iOS is stricter than browsers: a remote URL served as
|
|
199
|
+
* `application/octet-stream` with an opaque `.bin` name may fail before
|
|
200
|
+
* probing the actual audio payload. When the payload already looks like
|
|
201
|
+
* audio, cache it locally with an iOS-playable extension before playback.
|
|
202
|
+
*/
|
|
203
|
+
export function shouldCacheAudioForIosPlayback(opts: {
|
|
204
|
+
src?: string | null;
|
|
205
|
+
mime?: string | null;
|
|
206
|
+
fileName?: string | null;
|
|
207
|
+
originalName?: string | null;
|
|
208
|
+
duration?: number | string | null;
|
|
209
|
+
waveForm?: string | null;
|
|
210
|
+
}): boolean {
|
|
211
|
+
const src = opts.src || '';
|
|
212
|
+
if (!/^https?:\/\//i.test(src)) {return false;}
|
|
213
|
+
|
|
214
|
+
const mime = (opts.mime || '').toLowerCase().split(';')[0]!.trim();
|
|
215
|
+
const urlName = filenameFromUrl(src);
|
|
216
|
+
const candidates = [urlName, opts.fileName || '', opts.originalName || ''];
|
|
217
|
+
const hasIosPlayableName = candidates.some((value) =>
|
|
218
|
+
IOS_AUDIO_PLAYBACK_EXT_RE.test(value)
|
|
219
|
+
);
|
|
220
|
+
if (hasIosPlayableName && mime.startsWith('audio/')) {return false;}
|
|
221
|
+
|
|
222
|
+
return isLikelyAudio(mime, opts.fileName, src, {
|
|
223
|
+
duration: opts.duration,
|
|
224
|
+
waveForm: opts.waveForm,
|
|
225
|
+
originalName: opts.originalName,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export function getIosAudioPlaybackCacheExtension(opts: {
|
|
230
|
+
mime?: string | null;
|
|
231
|
+
fileName?: string | null;
|
|
232
|
+
originalName?: string | null;
|
|
233
|
+
url?: string | null;
|
|
234
|
+
}): string {
|
|
235
|
+
const candidates = [
|
|
236
|
+
opts.fileName,
|
|
237
|
+
opts.originalName,
|
|
238
|
+
filenameFromUrl(opts.url),
|
|
239
|
+
getExtensionForMime(opts.mime),
|
|
240
|
+
];
|
|
241
|
+
for (const candidate of candidates) {
|
|
242
|
+
const ext = getLowerExtension(candidate);
|
|
243
|
+
if (ext && IOS_AUDIO_PLAYBACK_EXT_RE.test(ext)) {
|
|
244
|
+
return ext === '.mp4' ? '.m4a' : ext;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return '.m4a';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function isUnsupportedAudioForIosPlayback(opts: {
|
|
251
|
+
mime?: string | null;
|
|
252
|
+
fileName?: string | null;
|
|
253
|
+
originalName?: string | null;
|
|
254
|
+
url?: string | null;
|
|
255
|
+
}): boolean {
|
|
256
|
+
const mime = (opts.mime || '').toLowerCase().split(';')[0]!.trim();
|
|
257
|
+
if (mime === 'audio/webm' || mime === 'audio/ogg') {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
const candidates = [
|
|
261
|
+
opts.fileName,
|
|
262
|
+
opts.originalName,
|
|
263
|
+
filenameFromUrl(opts.url),
|
|
264
|
+
];
|
|
265
|
+
return candidates.some((candidate) => {
|
|
266
|
+
const ext = getLowerExtension(candidate);
|
|
267
|
+
return IOS_AUDIO_UNSUPPORTED_EXTENSIONS.includes(
|
|
268
|
+
ext as (typeof IOS_AUDIO_UNSUPPORTED_EXTENSIONS)[number]
|
|
269
|
+
);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
159
273
|
/**
|
|
160
274
|
* Ensures `fileName` ends with a valid extension. Strategy:
|
|
161
275
|
* 1. If the input already has an extension, return it unchanged.
|
|
@@ -57,7 +57,7 @@ export const useEventHandlers = (config?: IConfig): EventHandlersHook => {
|
|
|
57
57
|
if (config?.eventHandlers?.onMessageFailed) {
|
|
58
58
|
config.eventHandlers.onMessageFailed(event);
|
|
59
59
|
}
|
|
60
|
-
console.
|
|
60
|
+
console.warn('Message failed details:', {
|
|
61
61
|
message: event.message,
|
|
62
62
|
roomJID: event.roomJID,
|
|
63
63
|
messageType: event.messageType,
|
|
@@ -313,6 +313,11 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
313
313
|
`${user?.firstName || ''} ${user?.lastName || ''}`.trim() || selfId;
|
|
314
314
|
const fileSizeStr = data?.size != null ? String(data.size) : '';
|
|
315
315
|
|
|
316
|
+
const normalizedFileUri =
|
|
317
|
+
typeof data?.uri === 'string'
|
|
318
|
+
? data.uri.replace(/^assets-library:\/\//, 'file://')
|
|
319
|
+
: '';
|
|
320
|
+
|
|
316
321
|
if (!config?.disableSentLogic && !existingId) {
|
|
317
322
|
dispatch(
|
|
318
323
|
addRoomMessage({
|
|
@@ -335,8 +340,8 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
335
340
|
isSystemMessage: 'false',
|
|
336
341
|
isMediafile: 'true',
|
|
337
342
|
fileName: data?.name,
|
|
338
|
-
location:
|
|
339
|
-
locationPreview:
|
|
343
|
+
location: normalizedFileUri,
|
|
344
|
+
locationPreview: normalizedFileUri,
|
|
340
345
|
mimetype: type,
|
|
341
346
|
originalName: data?.name,
|
|
342
347
|
size: fileSizeStr,
|
|
@@ -408,10 +413,7 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
408
413
|
// legacy library items — those can't be read as files. Coerce
|
|
409
414
|
// to a file:// scheme when possible so the body is a real blob.
|
|
410
415
|
const fileBlob = {
|
|
411
|
-
uri:
|
|
412
|
-
typeof data?.uri === 'string'
|
|
413
|
-
? data.uri.replace(/^assets-library:\/\//, 'file://')
|
|
414
|
-
: data?.uri,
|
|
416
|
+
uri: normalizedFileUri || data?.uri,
|
|
415
417
|
type:
|
|
416
418
|
data?.type ||
|
|
417
419
|
data?.mimeType ||
|
|
@@ -492,6 +494,10 @@ export const useSendMessage = (_configOverride?: IConfig) => {
|
|
|
492
494
|
store.getState()?.chatSettingStore?.client,
|
|
493
495
|
].find((c: any) => c && c.status === 'online');
|
|
494
496
|
if (effectiveMediaClient) {
|
|
497
|
+
effectiveMediaClient.setActiveRoomJid?.(activeRoomJID);
|
|
498
|
+
await Promise.resolve(
|
|
499
|
+
effectiveMediaClient.prioritizeRoomPresence?.(activeRoomJID)
|
|
500
|
+
).catch(() => false);
|
|
495
501
|
effectiveMediaClient.sendMediaMessageStanza(
|
|
496
502
|
activeRoomJID,
|
|
497
503
|
messagePayload,
|
|
@@ -429,7 +429,14 @@ const reducers = {
|
|
|
429
429
|
}
|
|
430
430
|
},
|
|
431
431
|
clearVisibleRoom: (state: WritableDraft<RoomMessagesState>) => {
|
|
432
|
+
const jid = state.visibleRoomJID;
|
|
432
433
|
state.visibleRoomJID = null;
|
|
434
|
+
|
|
435
|
+
if (jid && state.rooms[jid]) {
|
|
436
|
+
const room = state.rooms[jid];
|
|
437
|
+
const t = room.lastViewedTimestamp || 0;
|
|
438
|
+
room.unreadMessages = t > 0 ? countNewerMessages(room.messages, t) : 0;
|
|
439
|
+
}
|
|
433
440
|
},
|
|
434
441
|
/**
|
|
435
442
|
* Stash a JID that a push notification asked us to open before
|
package/src/types/types.ts
CHANGED
|
@@ -248,6 +248,16 @@ export interface IConfig {
|
|
|
248
248
|
// ----- header / nav -----
|
|
249
249
|
disableHeader?: boolean;
|
|
250
250
|
disableMedia?: boolean;
|
|
251
|
+
/**
|
|
252
|
+
* Enable in-chat voice-message recording. **Opt-in — off by default.**
|
|
253
|
+
* When `true`, an idle input (no text, no attachments) shows a
|
|
254
|
+
* microphone in the send-button slot; tap → start recording → stop &
|
|
255
|
+
* send. iOS apps need `NSMicrophoneUsageDescription` in Info.plist
|
|
256
|
+
* (add via `expo-av`'s plugin block in `app.json`). Receiving voice
|
|
257
|
+
* messages from other clients (incl. legacy web `.bin` voicemails) is
|
|
258
|
+
* independent of this flag — incoming audio plays regardless.
|
|
259
|
+
*/
|
|
260
|
+
enableAudio?: boolean;
|
|
251
261
|
chatHeaderBurgerMenu?: boolean;
|
|
252
262
|
// Hide the burger icon entirely (the icon that opens the chatHeader-
|
|
253
263
|
// BurgerMenu dropdown). `chatHeaderBurgerMenu` controls dropdown
|
|
@@ -517,6 +527,9 @@ export interface ModalFile {
|
|
|
517
527
|
fileName: string;
|
|
518
528
|
fileURL: string;
|
|
519
529
|
mimetype: string;
|
|
530
|
+
originalName?: string;
|
|
531
|
+
duration?: number | string;
|
|
532
|
+
waveForm?: string;
|
|
520
533
|
}
|
|
521
534
|
|
|
522
535
|
// Re-export so middleware/hooks that historically import from `types`
|