@robono/messaging-react-native 0.1.0 → 0.3.0

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.
Files changed (101) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +160 -8
  3. package/SBOM.spdx.json +1985 -209
  4. package/dist/account.d.ts +15 -0
  5. package/dist/account.js +27 -0
  6. package/dist/call-message.js +7 -1
  7. package/dist/calling.js +5 -9
  8. package/dist/conversation-details.d.ts +24 -0
  9. package/dist/conversation-details.js +83 -0
  10. package/dist/emoji-text.d.ts +2 -0
  11. package/dist/emoji-text.js +8 -0
  12. package/dist/expo-download.d.ts +3 -0
  13. package/dist/expo-download.js +43 -0
  14. package/dist/expo-history.d.ts +3 -0
  15. package/dist/expo-history.js +59 -0
  16. package/dist/expo-media.d.ts +1 -0
  17. package/dist/expo-media.js +69 -43
  18. package/dist/expo-messenger.d.ts +35 -0
  19. package/dist/expo-messenger.js +39 -0
  20. package/dist/expo-notifications.d.ts +31 -0
  21. package/dist/expo-notifications.js +92 -0
  22. package/dist/expo-outbox.d.ts +13 -0
  23. package/dist/expo-outbox.js +82 -0
  24. package/dist/expo-privacy.d.ts +4 -0
  25. package/dist/expo-privacy.js +7 -0
  26. package/dist/expo-saved.d.ts +24 -0
  27. package/dist/expo-saved.js +76 -0
  28. package/dist/expo-screen.d.ts +42 -0
  29. package/dist/expo-screen.js +557 -0
  30. package/dist/expo-social.d.ts +3 -0
  31. package/dist/expo-social.js +21 -0
  32. package/dist/expo-thumbnails.d.ts +9 -0
  33. package/dist/expo-thumbnails.js +68 -0
  34. package/dist/expo.d.ts +2 -36
  35. package/dist/expo.js +2 -429
  36. package/dist/extras-lifecycle.d.ts +2 -0
  37. package/dist/extras-lifecycle.js +27 -0
  38. package/dist/extras.d.ts +49 -0
  39. package/dist/extras.js +49 -0
  40. package/dist/forward.d.ts +13 -0
  41. package/dist/forward.js +62 -0
  42. package/dist/group-editor.d.ts +18 -0
  43. package/dist/group-editor.js +98 -0
  44. package/dist/header-calls.d.ts +18 -0
  45. package/dist/header-calls.js +45 -0
  46. package/dist/icons.d.ts +1 -1
  47. package/dist/inbox-search.d.ts +11 -0
  48. package/dist/inbox-search.js +42 -0
  49. package/dist/inbox.d.ts +19 -0
  50. package/dist/inbox.js +52 -0
  51. package/dist/index.d.ts +76 -3
  52. package/dist/index.js +648 -167
  53. package/dist/media-controller.d.ts +21 -0
  54. package/dist/media-controller.js +157 -3
  55. package/dist/media-readiness.d.ts +1 -1
  56. package/dist/media-ui.d.ts +27 -5
  57. package/dist/media-ui.js +95 -29
  58. package/dist/message-links.d.ts +5 -0
  59. package/dist/message-links.js +30 -0
  60. package/dist/message-menu.d.ts +28 -0
  61. package/dist/message-menu.js +24 -0
  62. package/dist/message-order.d.ts +7 -0
  63. package/dist/message-order.js +27 -0
  64. package/dist/messenger-video-view.d.ts +8 -0
  65. package/dist/messenger-video-view.js +46 -0
  66. package/dist/native-outbox.d.ts +55 -0
  67. package/dist/native-outbox.js +53 -0
  68. package/dist/photo-gesture.d.ts +20 -0
  69. package/dist/photo-gesture.js +52 -0
  70. package/dist/pollVoteQueue.d.ts +3 -0
  71. package/dist/pollVoteQueue.js +29 -0
  72. package/dist/polls.d.ts +7 -2
  73. package/dist/polls.js +89 -20
  74. package/dist/popup.d.ts +51 -0
  75. package/dist/popup.js +73 -0
  76. package/dist/quick-send.d.ts +15 -0
  77. package/dist/quick-send.js +26 -0
  78. package/dist/recent-media.js +1 -0
  79. package/dist/safety.d.ts +10 -1
  80. package/dist/safety.js +29 -8
  81. package/dist/saved.d.ts +10 -0
  82. package/dist/saved.js +51 -0
  83. package/dist/search.d.ts +9 -0
  84. package/dist/search.js +59 -0
  85. package/dist/social.d.ts +25 -0
  86. package/dist/social.js +31 -0
  87. package/dist/translation-settings.d.ts +12 -0
  88. package/dist/translation-settings.js +16 -0
  89. package/dist/use-quote-gesture.d.ts +5 -1
  90. package/dist/use-quote-gesture.js +35 -17
  91. package/dist/visual/RobonoIcon.js +2 -1
  92. package/dist/visual/WeatherArtwork.d.ts +9 -0
  93. package/dist/visual/WeatherArtwork.js +43 -0
  94. package/dist/visual/weather-artwork.d.ts +17 -0
  95. package/dist/visual/weather-artwork.js +86 -0
  96. package/dist/visual/weather-conditions.d.ts +5 -0
  97. package/dist/visual/weather-conditions.js +2 -0
  98. package/dist/voice-composer.js +2 -2
  99. package/dist/voice-waveform.d.ts +2 -0
  100. package/dist/voice-waveform.js +21 -0
  101. package/package.json +41 -5
package/CHANGELOG.md CHANGED
@@ -1,5 +1,70 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 — 2026-11-03
4
+
5
+ Add the complete ExpoMessenger setup and supplied inbox search, contact/shared-media, group owner, replies and pinned-message screens. Reuse Messenger popup boundaries and composer. Add opt-in native Apple/Google notification registration with account-safe logout, and expiring local received history. Notification credentials remain on the customer server.
6
+
7
+ Requires matching service migrations 181–186 and coordinated package publication. Physical-device notification delivery is a separate acceptance check.
8
+
9
+
10
+ Correct navigation scope: Saved is in the account-level Messages menu, not the contact menu. Search this chat uses an inline bar with previous/next matches. The native inbox has separate chat-list search and retains media adapters when opening Saved.
11
+
12
+ Refine popup interiors with grouped Saved/Search rows, aligned translation controls, consistent form fields, a subtle header divider, and a readable content width on desktop. Preserve the approved app-height black frame and existing translation behavior.
13
+
14
+ Use one Messenger popup frame and title/X row across search, contact options, Saved, forwarding, polls, confirmations, weather, tracking and social previews. Use the same app-height, black frame, raised title/X, and narrow 0/8/4/8 inner spacing as tracking/social, including forms and confirmations. Keep the frame inside phone safe areas. Keep inbox actions and delete confirmation in the same modal.
15
+
16
+ Move Saved from a standalone header bookmark into its own three-dot menu entry, matching Messenger’s Saved navigation. Dismiss the options modal before opening Saved on iOS.
17
+
18
+ When Privacy Lens is enabled, place messages above the clear reading strip. Keep short chats scrollable into the strip and leave new arrivals above it until the user scrolls.
19
+
20
+ Tighten Yes/No bubbles to content width, with an inline poll icon and compact answer row. Give polls an outlined neutral card and remove inline timestamps; time remains in the swipe details.
21
+
22
+ Show Messenger’s condition-specific weather artwork for current, hourly and daily forecasts, using compact inline icons.
23
+
24
+ Expand weather to the same safe-area popup as tracking and social, with the raised header and dark backdrop. Let forecast content scroll within the available space.
25
+
26
+ Circle the centered latest-message arrow. Fade it out during scrolling and restore it after a 600ms pause when still away from the latest message.
27
+
28
+ Preserve independently consented address shares while moving between chats or the inbox. Stop only the selected share when End tracking is pressed; app background/logout still stop capture.
29
+
30
+ Place social-share Preview buttons beside the bubble and omit inline timestamps. Use the expanded safe-area popup, dark backdrop and raised header shared with tracking; let the social player fill available space.
31
+
32
+ Keep the sharing button and single avatar row within the measured address-bubble height.
33
+
34
+ Enlarge tracking names, speed/distance and ETA details. Pass the selected units and current time to map adapters so participant callouts stay synchronized.
35
+
36
+ Keep the expanded tracking popup within native safe areas. Size the map from the remaining popup space, with compact controls and a bounded scrolling participant list.
37
+
38
+ Expand live tracking to an inset app-sized popup. Add 48-point circular participant avatar buttons below the sharing control; tapping an avatar opens the map with that person selected.
39
+
40
+ Open live tracking from the full address-bubble body while keeping the address link and sharing button separate. Darken the shared popup backdrop to 85% black.
41
+
42
+ Keep city, state and ZIP in address links when the street is not followed by a comma. Reduce address-bubble vertical padding.
43
+
44
+ Tighten address bubbles: place a compact outlined “Allow tracking” button with a location icon beside the bubble toward the center of the chat, omit the empty participant row, and show the time only in the swipe information reveal.
45
+
46
+ Place enabled Camera capture inside Attach beside the photo/video library options, matching Messenger. Keep it available when library browsing is hidden, and stage captured media before Send.
47
+
48
+ Fix photo pinch-to-zoom and panning: Messenger’s 1–5× range, actual image bounds, smooth transitions when fingers join/leave, and no accidental toolbar toggle after a gesture. Support browser touch and trackpad pinch.
49
+
50
+ Match Messenger’s information/quote swipe travel and return timing; reveal sent/read information behind ordinary bubbles. Remove photo/video timestamp overlays and redundant sent/read checkmarks.
51
+
52
+ Select multiple photos, videos or files in one picker visit, preserving order, draft thumbnails, the remaining ten-file limit, and local-until-Send behavior. Keep editing/call replies single-file. Preserve pending attachments when a host recreates its preview callback while typing. Use Messenger’s full reaction catalogue.
53
+
54
+ ## 0.2.0
55
+
56
+ Use the compact Messenger media toolbar, autoplay video after audio setup, and offer native full-screen playback. Dismiss iOS menus before presenting Saved media, Forward/Delete/Report or Search; keep native pickers free of a competing modal. Reserve the actual timestamp width so edited messages do not overlap it.
57
+
58
+ Add shared Edit/Delete actions, draft-preserving composer editing, delete confirmation and search/quote navigation. Media adapters report opening/playback independently of bubble visibility. Media replacement/removal, authorized forwarding, persistent Saved copies and native outgoing draft recovery are implemented. Physical iPhone checks cover selected flows; physical Android acceptance remains outstanding.
59
+
60
+ Add text/voice translation to text or voice, shared translation popup, browser/Expo spoken playback and expiring-result cleanup. Add optional viewer downloads (off by default): device photo library, iPhone Save to Files sheet and bounded Android folder export. Streamed video exports an authorized local copy without replacing playback. Requires expo-file-system >=55.0.5. iPhone checks cover playback, Saved files, restart recovery and popup transitions. Android device acceptance and physical export-sheet checks remain pending.
61
+
62
+ Add `MessagingInbox`, the shared search popup and optional expiring typing/online labels in the existing header. Clear private unread counts independently of public read receipts. Closed polls disable their controls on both native and web renderers. Requires the matching 0.2.0 core release; iPhone fixture acceptance is recorded separately from Android acceptance.
63
+
64
+ Render unfinished sends as ordinary chat bubbles with compact status icons and in-place retry. Keep the composer available during attachment sends. Stage browser and Expo attachments locally until Send; add native thumbnails and preview without consuming the draft.
65
+
66
+ Use the server-provided total member count for large groups instead of counting a partial member page.
67
+
3
68
  ## 0.1.0
4
69
 
5
70
  Optional messaging screens and media controls, attachment composer, recording, playback, quoting, reactions, polls, translation, transcription, block and report flows. Expo adapters and optional calling integration.
package/README.md CHANGED
@@ -1,6 +1,43 @@
1
1
  # Optional Robono messaging screens
2
2
 
3
- Use a ready-made direct or group conversation screen, replace its sections, or compose the exported components into your own layout. This package is optional and adds no navigation, global audio configuration or push handlers to your app. The shared icon controls require `react-native-svg` (install it with your framework’s native dependency installer).
3
+ Use a ready-made direct or group conversation screen, replace its sections, or compose the exported components into your own layout. Use `ExpoMessenger` for the complete inbox and conversation flow, or the individual components inside your existing navigation. Notification registration is explicit; nothing requests permission on mount. The shared icon controls require `react-native-svg` (install it with your framework’s native dependency installer).
4
+
5
+ ## Recommended installation
6
+
7
+ Connect `createRobonoMessengerServer` from `@robono/server` at one authenticated
8
+ HTTPS route. It supplies managed private attachments. Create one connection per
9
+ signed-in account, outside repeated renders:
10
+
11
+ ```tsx
12
+ import {createExpoMessenger, ExpoMessenger} from '@robono/messaging-react-native/expo';
13
+ const messenger = createExpoMessenger({
14
+ endpoint: 'https://your-app.example/api/robono',
15
+ userId: session.userId,
16
+ getAccessToken: () => session.accessToken(),
17
+ isCallActive: () => calls.isActive(),
18
+ });
19
+ <ExpoMessenger {...messenger} userId={session.userId}
20
+ companyName="Your company" contacts={contacts} />
21
+ // On logout, before destroying the user's session:
22
+ try { await messenger.signOut(); } finally { await session.signOut(); }
23
+ ```
24
+
25
+ Install the native dependencies below and rebuild both platforms. For alerts
26
+ outside the app, use the explicit `./expo-notifications` connector and follow
27
+ `@robono/server/NOTIFICATIONS.md`: iPhone needs **your** Apple Team ID, APNs Key ID,
28
+ private .p8 key and Bundle ID; Android needs **your** Firebase project, app
29
+ configuration and a server-only service account. Never ship private keys in the
30
+ app. Website chat itself does not require these mobile credentials.
31
+
32
+ The supplied group owner, shared-media, reply and pinned-message screens use the
33
+ same popup boundaries as Messenger. Global search and group controls require the
34
+ matching server and service migrations. Imported groups need a server-assigned
35
+ owner before users can edit them. Optional offline received history is disabled
36
+ by default; its network-selected expiry is honored and it is read-only offline.
37
+ Revocation while disconnected is not known until reconnection or expiry. Logout
38
+ clears the local account's history. `persistence:false` disables these local stores.
39
+
40
+ ## Individual screen inside existing navigation
4
41
 
5
42
  ```tsx
6
43
  import {MessagingScreen} from '@robono/messaging-react-native';
@@ -27,7 +64,7 @@ Text uses a send icon; `appearance.labels.send` remains its accessible label. Vo
27
64
 
28
65
  Supply `attachmentPreview(message)` to resolve `{uri?, waveform?}` after checking the current user's media access. `uri` is an image thumbnail (a poster frame for video); `waveform` contains 32 normalized amplitude values between 0 and 1. These stay in component state, not in the message payload. Without metadata the SDK shows a neutral media tile or waveform track. `openAttachment` remains responsible for authorized media access. The Expo screen supplies inline voice playback and the shared full-screen media viewer. To connect a different audio engine, supply `components.VoiceMessage` and render the exported `VoicePlayback` with its playback state and callbacks. `MediaViewer`, `ZoomablePhoto` and `MediaPlaybackControls` are also exported for hosts with their own media engines.
29
66
 
30
- Photos, videos and files share an Attach menu. Set `appearance.showCamera` to offer Camera alongside them; photo messaging must also be enabled. The option defaults off for existing integrations. Camera calls `pickAttachment('image', {...limits, source: 'camera'})`, so captures follow the same photo restrictions and review/upload process. Hosts supplying their own media callback must handle that source explicitly. The Expo adapter requests camera permission only on selection and opens the device camera on iOS and Android. Configure the `expo-image-picker` plugin's `cameraPermission` explanation in your native build. Cancelling or refusing permission sends nothing.
67
+ Photos, videos and files share an Attach menu. Set `appearance.showCamera` to offer Camera inside that menu beside the library options; photo or video messaging must also be enabled. The option defaults off for existing integrations. Camera calls `pickAttachment('image', {...limits, source: 'camera'})`, so captures follow the same photo restrictions and review/upload process. Hosts supplying their own media callback must handle that source explicitly. The Expo adapter requests camera permission only on selection and opens the device camera on iOS and Android. Configure the `expo-image-picker` plugin's `cameraPermission` explanation in your native build. Cancelling or refusing permission sends nothing.
31
68
 
32
69
  ## Reuse or replace components
33
70
 
@@ -54,9 +91,15 @@ This entry targets Expo SDK 55–56; the core components do not require Expo. Co
54
91
  ```tsx
55
92
  import {
56
93
  ExpoMessagingScreen, createExpoMessagingStorage,
57
- createExpoMessagingAudioSession,
94
+ createExpoMessagingAudioSession, createExpoMessagingClient,
58
95
  } from '@robono/messaging-react-native/expo';
59
96
 
97
+ const messagingClient = createExpoMessagingClient({
98
+ url: appConfig.messagingEndpoint,
99
+ userId: session.userId,
100
+ getAccessToken: () => sessions.accessToken(),
101
+ });
102
+
60
103
  const storage = createExpoMessagingStorage({
61
104
  url: appConfig.messagingMediaEndpoint,
62
105
  getAccessToken: () => sessions.accessToken(),
@@ -136,13 +179,13 @@ The website preview renders the same bubbles, inline voice controls, full-screen
136
179
 
137
180
  The standard chat uses compact grouped bubbles, timestamps at the lower right, inline voice controls and an expandable attachment tray below the composer. Attach dismisses the keyboard; tap it again to return to typing. Android Back closes the tray first. The microphone remains available beside the text field, including while text is typed; Send is enabled when there is text or a finished voice recording. Camera remains available when capture is enabled, including with typed text or a reviewed voice recording. Captures join the existing pending attachments. New designs start with a light chat palette; existing saved colors remain unchanged. The builder’s “Use classic chat colors” action applies the default palette to the draft without changing enabled features.
138
181
 
139
- Voice-only conversations use Robono Messenger’s compact composer: the duration-limit placeholder, embedded microphone and adjacent Send control. The Expo adapter records and reviews audio inline, with elapsed time, microphone metering, playback and removal before sending. The builder uses the same controls with a local browser microphone recording; no audio is uploaded from the preview. When texting is enabled, tap the microphone to record in the composer and tap it again to stop. Each completed recording becomes a separate playable attachment in the shared horizontal row, and the microphone is available for another recording. Typed text is preserved; Send submits the voice message and any accompanying text as separate messages. Custom media adapters can use `components.VoiceComposer`, `VoiceMessageComposer` and `VoiceDraftPlayback`; `renderTextComposer` restores the text controls alongside the reviewed recording.
182
+ Voice-only conversations use Robono Messenger’s compact composer: the duration-limit placeholder, embedded microphone and adjacent Send control. The Expo adapter records and reviews audio inline, with elapsed time, microphone metering, playback and removal before sending. The builder uses the same controls with a local browser microphone recording; no audio is uploaded from the preview. When texting is enabled, tap the microphone to record in the composer and tap it again to stop. Each completed recording becomes a separate playable attachment in the shared horizontal row, and the microphone is available for another recording. Typed text is preserved; Send puts accompanying text on the last attachment as its caption. Custom media adapters can use `components.VoiceComposer`, `VoiceMessageComposer` and `VoiceDraftPlayback`; `renderTextComposer` restores the text controls alongside the reviewed recording.
140
183
 
141
- Recent attachments can appear directly beneath the attachment buttons. Photos, Videos and Document filter this strip; tapping the selected category again shows all enabled types. Tapping a thumbnail adds it above the composer as a pending attachment; its magnifying-glass button opens a preview instead. Remove unwanted attachments or press Send to submit the selection with any typed text. Camera starts capture. When no recent-media source is supplied, the category buttons open the device picker. Supply `attachmentChoices` with an ID, kind, name, and optional thumbnail URI/duration. Only enabled attachment types appear. With `MessagingScreen`, selecting a tile calls `pickAttachment` with `options.attachmentId`; use `options.intent` to distinguish selection (`send`, retained for adapter compatibility) from preview. Returning photo, video or document media stages it in the composer; returning null cancels without selecting it. Voice recordings also become pending attachments after recording stops. With `ExpoMessagingScreen`, supply `resolveAttachmentChoice(id, signal)` to return an authorized cache copy; the standard preview, validation, send and cleanup flow handles the rest. Keep originals in the user's library untouched. The host controls library access and which recent items it supplies.
184
+ Recent attachments can appear directly beneath the attachment buttons. Photos, Videos and Files filter this strip; tapping the selected category again shows all enabled types. Tapping a thumbnail adds it above the composer as a pending attachment; its magnifying-glass button opens a preview instead. Remove unwanted attachments or press Send to submit the selection with any typed text. Camera starts capture. When no recent-media source is supplied, the category buttons open the device picker. Supply `attachmentChoices` with an ID, kind, name, and optional thumbnail URI/duration. Only enabled attachment types appear. With `MessagingScreen`, selecting a tile calls `pickAttachment` with `options.attachmentId`; use `options.intent` to distinguish selection (`send`, retained for adapter compatibility) from preview. Returning photo, video or document media stages it in the composer; returning null cancels without selecting it. Voice recordings also become pending attachments after recording stops. With `ExpoMessagingScreen`, supply `resolveAttachmentChoice(id, signal)` to return an authorized cache copy; the standard preview, validation, send and cleanup flow handles the rest. Keep originals in the user's library untouched. The host controls library access and which recent items it supplies.
142
185
 
143
186
  Camera capture and library selection are separate controls. `appearance.showPhotoLibrary` and `showVideoLibrary` hide library choices without removing the corresponding message-type permission needed for camera captures. Both default to true for existing integrations. The builder manages these together with Camera, so enabling capture does not select Photos/Videos or insert example media. Parent and network message-type permissions remain enforced.
144
187
 
145
- The Expo adapter prepares voice assets in private storage when recording stops, retaining local playback copies until removal, submission or disposal. This does not send a chat message. Send submits all selected attachments in order, followed by any typed text. Custom adapters can supply components.VoiceAttachment for draft playback and releaseAttachment for local cleanup.
188
+ The Expo adapter keeps selected and recorded attachments locally until Send. Recording stops into a playable draft without uploading. Send immediately queues the bubbles, then uploads the selected files. A caption belongs to the final attachment; a quote belongs to the first. The batch preserves selection order when uploads finish out of order. Custom adapters can supply components.VoiceAttachment for draft playback and releaseAttachment for local cleanup.
146
189
 
147
190
 
148
191
  ## Group conversations, reactions and polls
@@ -159,8 +202,117 @@ Use `ExpoMessagingCallingScreen` from `@robono/messaging-react-native/expo-calli
159
202
 
160
203
  ### Blocking, reporting, reactions and language tools
161
204
 
162
- The default header’s three-dot menu provides Block/Unblock and Report when the authenticated backend advertises safety support. Hold a received bubble to report that message. `onContactOptions` optionally replaces the supplied contact menu with your existing safety flow. The exported `MessagingSafety` component can also be composed into your screen.
205
+ The conversation header’s three-dot menu includes Search this chat, plus Block/Unblock and Report when the authenticated backend advertises safety support. Saved belongs to the account and is in the separate Messages menu, never under a contact’s name. Hold a received bubble to report that message. `onContactOptions` optionally replaces the supplied contact menu with your existing safety flow. The exported `MessagingSafety` component can also be composed into your screen.
163
206
 
164
207
  Blocking retains history and stops direct messages and calls for that pair in your app. Shared group messages remain visible. Reporting is separate: it shares the selected message, or up to five recent incoming messages, and the reason with your app’s moderators. It confirms success only after storage acknowledges the report. The SDK reuses the request ID on retry. Owners and administrators review reports in the Messaging workspace; private media is reviewed through your app’s authorized storage tools.
165
208
 
166
- Enable Reactions to show an emoji ribbon beside the long-pressed bubble, or the hover smile icon on desktop. Selected reactions stay attached below the message. Polls are interactive chat messages created from the attachment menu. Transcript and Translate toggle small text immediately under the original; the original timestamp stays with the source message.
209
+ Enable Reactions to show an emoji ribbon beside the long-pressed bubble, or the hover smile icon on desktop. Selected reactions stay attached below the message. Polls are interactive chat messages created from the attachment menu. Transcript is a separate voice-message action. In the header's three-dot menu, choose translation **Off / Text / Voice** and languages once for the conversation. The saved choice controls Translate or Play Translation on eligible incoming messages; own messages and matching sender/target languages do not show it. The result has Show original / Show translation controls. Expo supplies translated-voice playback and its audio session; an explicit Play Translation action starts playback when ready. `language` supplies the initial target and `contact.language` / `participants[id].language` supply known sender languages, with a saved conversation incoming-language fallback. Defaults to Off. The Expo private outbox retains preferences across restarts on this device. Custom contact menus can call `client.setTranslationPreference({mode:'text',language:'es',sourceLanguage:'en'})`. Connect `MessagingClient.transformRequest` to the authenticated `createMessagingTransformBackendAdapter` on your server.
210
+
211
+ ### November 1 behavior update (unpublished)
212
+
213
+ The default palette follows Messenger. Existing saved customer colors remain in
214
+ place. Direct chats use the brand header; groups use Messenger’s blue header.
215
+ Bubble padding is fixed; the legacy `compact` property is accepted for backwards
216
+ compatibility but no longer changes core spacing.
217
+
218
+ Photo/video/file selections remain removable drafts; tapping a draft opens its
219
+ viewer without deleting the selection. Expo supplies small image/video previews
220
+ using `expo-image-manipulator` and `expo-video-thumbnails`; add those optional peers
221
+ when using the Expo entry. Copy uses `expo-clipboard`. Native media downloads use
222
+ photo-library permission; sharing uses the platform share sheet. New managed photo/video uploads have an authenticated preview (at most 480 pixels and 128 KiB) after the updated storage worker, inspector, media handler and migration 178 are deployed. Previews count toward normal storage/transfer usage. Older large uploads without a preview remain tap-to-open; originals over 2 MiB are never automatically downloaded to build thumbnails.
223
+
224
+ `appearance.showWaveform` controls display only. Verified waveform samples stay
225
+ in `media.waveform`. The playback track remains seekable when the waveform is
226
+ hidden. Managed storage computes waveform data independently of this preference.
227
+
228
+ Groups offer polls; direct chats offer a recipient-only Yes/No question whose
229
+ first answer is final. Both use the same app-height popup frame as tracking and social previews. Deploy migration
230
+ `20261101017400_messaging_captions_questions.sql` and the updated messaging handler
231
+ before releasing these SDK changes. Deploy the updated media inspector before the
232
+ updated managed-media handler. These source changes have not been published.
233
+
234
+ ### Optional downloads in the viewer
235
+
236
+ Select **Download button** in the website's **Features & preview → Appearance**, or
237
+ set `appearance.showDownloadButton: true`. The Expo viewer shows the same Download
238
+ action for photos, videos and files; it stays hidden by default. Photos and videos
239
+ save to the device photo library after the user grants permission. On iPhone,
240
+ documents open the native sheet with Save to Files. On Android, the user chooses a
241
+ folder and the document is copied there in bounded chunks. Cancelling creates no
242
+ file, and a failed copy removes its own partial output. Use `expo-file-system`
243
+ 55.0.5 or later for Android document saving. Originals remain in private storage.
244
+ This setting controls the visible action, not the authorization needed to view media.
245
+
246
+ `createExpoMessagingClient` keeps outgoing text, selected attachments and failed
247
+ sends in your app's private document storage, separated by endpoint and user.
248
+ `ExpoMessagingScreen` restores small previews and reuses the original upload/send
249
+ identity when retrying. Call `client.signOut()` on logout to remove that user's
250
+ saved work. `dispose()` preserves unfinished work for reopening. Use
251
+ `persistence: false` to disable storage. No received history or download links are
252
+ persisted by this store. The OS app sandbox protects these files; this is not an
253
+ additional application encryption layer.
254
+
255
+ The shared message menu and media preview include Forward and sender Delete.
256
+ Forward checks both chats and uploads a separate private attachment copy; retrying
257
+ uses the same send ID. Edits can replace/remove attachments before a recipient
258
+ opens them. Removing the only attachment requires text. Caption edits keep the
259
+ original file. The ordinary composer draft is retained throughout editing.
260
+
261
+ `MessagingInbox` offers Mute/Unmute and Delete chat on long press (right-click on
262
+ web), plus accessibility actions. Deletion clears only that user's view, up to the
263
+ message shown when confirmation opened. New messages bring the chat back. When
264
+ composing your own native navigation, pass
265
+ `onDeleted={id => messagingClient.forgetConversation(id)}` to clear its local work.
266
+ Updated backend support is required; old adapters hide these controls.
267
+
268
+ ### Saved and multiple-message actions
269
+
270
+ Long press a message, then choose Select to select more rows. The compact action bar supports chronological forwarding and deletion of eligible unread outgoing messages. A single selection also supports Copy, Save and Edit. Back clears the selection.
271
+
272
+ `createExpoMessagingClient` also supplies Saved: explicit local text and attachment copies in the app-private directory, separated by endpoint, account and namespace. The account-level Messages menu opens Saved from all conversations. Standalone chats have no account toolbar; place account navigation on the host inbox. For inbox navigation, keep one `MessagingProvider` mounted around `MessagingConversation` / `MessagingInbox` and pass `headerActions={<MessagingAccountMenu/>}` to the inbox; the Expo `renderConversation` callback supplies the same media adapters to that provider. Saving rechecks message access before and after making the copy, and marks incoming content consumed. Saved copies are independent of network retention; they never reuse signed URLs. `client.signOut()` deletes this account’s saved copies. Disabling persistence also disables Saved. Device storage is not a cloud backup or an additional app encryption layer. For a custom engine, supply a `MessagingSavedStore` to `MessagingClient` and `openSavedAttachment` to the shared screen.
273
+
274
+ ### Social previews
275
+
276
+ Install `react-native-webview` with the Expo peer dependencies and rebuild the native app. `ExpoMessagingScreen` supplies the player and the standard shared popup; a custom engine can supply `components.SocialPlayer`. The updated server adapter and hosted messaging endpoint advertise support. Recognized links gain a small play action, while tapping the link still opens the original app/site. Players are loaded only after an explicit tap and fresh message authorization, require explicit playback, and are removed on close/background/navigation. Opening a player stops the current voice-message player and uses the supplied audio-session coordinator. No application cookies or local-file access are shared with the embedded page. Some providers/private posts cannot be embedded; the popup keeps an Open-original link.
277
+
278
+ The same provider parser is used by Messenger, the browser and the backend, including Snapchat and Rumble. Preview opens contribute to the per-network `social.opened` metric. This source change still requires coordinated endpoint and package deployment; installing a newer UI against an older adapter does not enable unsupported controls.
279
+
280
+
281
+ ### Multiple selections from one picker
282
+
283
+ The supplied Expo and browser pickers allow selecting several photos, videos, or
284
+ files in one visit, up to ten total pending attachments. Selection stays local:
285
+ each item has a removable thumbnail, preview is a separate tap, and upload begins
286
+ only after Send. Order is preserved, the quote belongs to the first attachment,
287
+ and the caption belongs to the last. Editing and call replies select one item.
288
+
289
+ A custom `pickAttachment(kind, options)` may return one `MessageMedia`, an ordered
290
+ `MessageMedia[]`, or `null`. Honor `options.maxCount` (the remaining slots) and the
291
+ existing size/type/duration limits. Existing single-file adapters still work.
292
+ The low-level `MessagingMediaDevice.pickMany` method is optional;
293
+ `MessagingMediaController.pickMany` falls back to the single picker when absent.
294
+ Cancellation or an invalid selection releases all private copies without sending
295
+ or accepting a partial batch. Never delete the user's library originals.
296
+
297
+ Conversation search stays inline below the chat header with a match count and previous/next controls. Its authenticated search remains scoped to the open conversation. `MessagingInbox` provides a separate Search chats field over loaded chat titles and last-message text; optional `searchText(row)` adds the host's local retained-message index (used in the native review). It does not imply a server-wide search across unloaded conversations.
298
+
299
+ ### Company, account and call controls
300
+
301
+ `companyName` is the customer’s company name, not Robono’s. It labels the inbox
302
+ only; when omitted, the configured appearance name is used. Conversation screens
303
+ show only the friend/group header, never the company heading or account menu.
304
+ The main three-dot dropdown contains Account and Saved. Supply `account` with
305
+ `name`, optional `avatarUrl`, `phone`, and `email`. `onEditProfile` and `onSignOut`
306
+ are optional host actions; unsupported actions are hidden. Sign-out must revoke
307
+ your app session and call the messaging client’s `signOut()` to clear local data.
308
+ The Account screen dismisses before opening the host’s profile/sign-out flow.
309
+
310
+ Direct conversations keep the customer’s accent header. Groups use Messenger’s
311
+ blue `#1F5F7A` header with light text and icons. Phone/video icons use the same ink.
312
+ Supply `callActions.voice`/`video` only while the contact/group is eligible for
313
+ those calls. `callActions.phoneNumber` supplies a direct contact’s callable number,
314
+ and `callActions.phone(number)` can override opening the system `tel:` handler.
315
+ The phone button opens Messenger’s method choices when a number exists; otherwise
316
+ it starts the available internet call directly. Groups never show a carrier choice.
317
+ `MessagingCallingScreen` and `ExpoMessagingCallingScreen` still accept existing
318
+ `onCall`/`onVideoCall` callbacks and use these same controls.