@kesha-antonov/react-native-chat 4.1.0 → 4.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 (253) hide show
  1. package/README.md +306 -62
  2. package/lib/Actions.d.ts +5 -5
  3. package/lib/Actions.d.ts.map +1 -1
  4. package/lib/Actions.js +28 -39
  5. package/lib/Actions.js.map +1 -1
  6. package/lib/Avatar.d.ts.map +1 -1
  7. package/lib/Avatar.js +22 -27
  8. package/lib/Avatar.js.map +1 -1
  9. package/lib/Bubble/index.d.ts.map +1 -1
  10. package/lib/Bubble/index.js +138 -37
  11. package/lib/Bubble/index.js.map +1 -1
  12. package/lib/Bubble/styles.d.ts +47 -11
  13. package/lib/Bubble/styles.d.ts.map +1 -1
  14. package/lib/Bubble/styles.js +108 -57
  15. package/lib/Bubble/styles.js.map +1 -1
  16. package/lib/Bubble/types.d.ts +16 -1
  17. package/lib/Bubble/types.d.ts.map +1 -1
  18. package/lib/Chat/ChatKeyboardAvoidingView.d.ts +21 -0
  19. package/lib/Chat/ChatKeyboardAvoidingView.d.ts.map +1 -0
  20. package/lib/Chat/ChatKeyboardAvoidingView.js +15 -0
  21. package/lib/Chat/ChatKeyboardAvoidingView.js.map +1 -0
  22. package/lib/Chat/index.d.ts.map +1 -1
  23. package/lib/Chat/index.js +81 -28
  24. package/lib/Chat/index.js.map +1 -1
  25. package/lib/Chat/types.d.ts +36 -6
  26. package/lib/Chat/types.d.ts.map +1 -1
  27. package/lib/ChatAvatar.d.ts.map +1 -1
  28. package/lib/ChatAvatar.js +11 -17
  29. package/lib/ChatAvatar.js.map +1 -1
  30. package/lib/ChatContext.d.ts +29 -1
  31. package/lib/ChatContext.d.ts.map +1 -1
  32. package/lib/ChatContext.js +3 -0
  33. package/lib/ChatContext.js.map +1 -1
  34. package/lib/Color.d.ts.map +1 -1
  35. package/lib/Color.js +6 -2
  36. package/lib/Color.js.map +1 -1
  37. package/lib/Composer.d.ts +14 -1
  38. package/lib/Composer.d.ts.map +1 -1
  39. package/lib/Composer.js +63 -50
  40. package/lib/Composer.js.map +1 -1
  41. package/lib/Day/index.d.ts.map +1 -1
  42. package/lib/Day/index.js +7 -3
  43. package/lib/Day/index.js.map +1 -1
  44. package/lib/Day/styles.d.ts +6 -7
  45. package/lib/Day/styles.d.ts.map +1 -1
  46. package/lib/Day/styles.js +11 -13
  47. package/lib/Day/styles.js.map +1 -1
  48. package/lib/Icons.d.ts +24 -0
  49. package/lib/Icons.d.ts.map +1 -0
  50. package/lib/Icons.js +2 -0
  51. package/lib/Icons.js.map +1 -0
  52. package/lib/InputToolbar.d.ts +18 -5
  53. package/lib/InputToolbar.d.ts.map +1 -1
  54. package/lib/InputToolbar.js +223 -19
  55. package/lib/InputToolbar.js.map +1 -1
  56. package/lib/LoadEarlierMessages.d.ts.map +1 -1
  57. package/lib/LoadEarlierMessages.js +12 -7
  58. package/lib/LoadEarlierMessages.js.map +1 -1
  59. package/lib/Message/index.d.ts.map +1 -1
  60. package/lib/Message/index.js +10 -9
  61. package/lib/Message/index.js.map +1 -1
  62. package/lib/Message/styles.d.ts +1 -4
  63. package/lib/Message/styles.d.ts.map +1 -1
  64. package/lib/Message/styles.js +4 -4
  65. package/lib/Message/styles.js.map +1 -1
  66. package/lib/MessageAudio.d.ts +2 -1
  67. package/lib/MessageAudio.d.ts.map +1 -1
  68. package/lib/MessageAudio.js +121 -19
  69. package/lib/MessageAudio.js.map +1 -1
  70. package/lib/MessageLocation.d.ts +9 -0
  71. package/lib/MessageLocation.d.ts.map +1 -0
  72. package/lib/MessageLocation.js +85 -0
  73. package/lib/MessageLocation.js.map +1 -0
  74. package/lib/MessageText.d.ts +12 -1
  75. package/lib/MessageText.d.ts.map +1 -1
  76. package/lib/MessageText.js +38 -11
  77. package/lib/MessageText.js.map +1 -1
  78. package/lib/MessageVideo.d.ts +2 -1
  79. package/lib/MessageVideo.d.ts.map +1 -1
  80. package/lib/MessageVideo.js +156 -18
  81. package/lib/MessageVideo.js.map +1 -1
  82. package/lib/MessagesContainer/FlashList.d.ts +9 -0
  83. package/lib/MessagesContainer/FlashList.d.ts.map +1 -0
  84. package/lib/MessagesContainer/FlashList.js +23 -0
  85. package/lib/MessagesContainer/FlashList.js.map +1 -0
  86. package/lib/MessagesContainer/components/Item/index.d.ts +2 -1
  87. package/lib/MessagesContainer/components/Item/index.d.ts.map +1 -1
  88. package/lib/MessagesContainer/components/Item/index.js +23 -1
  89. package/lib/MessagesContainer/components/Item/index.js.map +1 -1
  90. package/lib/MessagesContainer/index.d.ts.map +1 -1
  91. package/lib/MessagesContainer/index.js +133 -42
  92. package/lib/MessagesContainer/index.js.map +1 -1
  93. package/lib/MessagesContainer/styles.d.ts +23 -7
  94. package/lib/MessagesContainer/styles.d.ts.map +1 -1
  95. package/lib/MessagesContainer/styles.js +25 -9
  96. package/lib/MessagesContainer/styles.js.map +1 -1
  97. package/lib/MessagesContainer/types.d.ts +22 -2
  98. package/lib/MessagesContainer/types.d.ts.map +1 -1
  99. package/lib/Models.d.ts +72 -0
  100. package/lib/Models.d.ts.map +1 -1
  101. package/lib/QuickReplies.d.ts +1 -1
  102. package/lib/QuickReplies.d.ts.map +1 -1
  103. package/lib/QuickReplies.js +13 -7
  104. package/lib/QuickReplies.js.map +1 -1
  105. package/lib/Reactions/MessageReactions.d.ts.map +1 -1
  106. package/lib/Reactions/MessageReactions.js +11 -10
  107. package/lib/Reactions/MessageReactions.js.map +1 -1
  108. package/lib/Reactions/ReactionPicker.d.ts.map +1 -1
  109. package/lib/Reactions/ReactionPicker.js +5 -3
  110. package/lib/Reactions/ReactionPicker.js.map +1 -1
  111. package/lib/Send.d.ts +2 -2
  112. package/lib/Send.d.ts.map +1 -1
  113. package/lib/Send.js +37 -37
  114. package/lib/Send.js.map +1 -1
  115. package/lib/SystemMessage.d.ts.map +1 -1
  116. package/lib/SystemMessage.js +8 -5
  117. package/lib/SystemMessage.js.map +1 -1
  118. package/lib/Theme.d.ts +148 -0
  119. package/lib/Theme.d.ts.map +1 -0
  120. package/lib/Theme.js +142 -0
  121. package/lib/Theme.js.map +1 -0
  122. package/lib/Time.d.ts.map +1 -1
  123. package/lib/Time.js +7 -5
  124. package/lib/Time.js.map +1 -1
  125. package/lib/TypingIndicator/index.d.ts.map +1 -1
  126. package/lib/TypingIndicator/index.js +4 -1
  127. package/lib/TypingIndicator/index.js.map +1 -1
  128. package/lib/TypingIndicator/styles.d.ts +2 -2
  129. package/lib/TypingIndicator/styles.d.ts.map +1 -1
  130. package/lib/TypingIndicator/styles.js +4 -5
  131. package/lib/TypingIndicator/styles.js.map +1 -1
  132. package/lib/components/AttachmentSheet.d.ts +28 -0
  133. package/lib/components/AttachmentSheet.d.ts.map +1 -0
  134. package/lib/components/AttachmentSheet.js +177 -0
  135. package/lib/components/AttachmentSheet.js.map +1 -0
  136. package/lib/components/BasicMarkdown.d.ts +12 -0
  137. package/lib/components/BasicMarkdown.d.ts.map +1 -0
  138. package/lib/components/BasicMarkdown.js +220 -0
  139. package/lib/components/BasicMarkdown.js.map +1 -0
  140. package/lib/components/ContextMenu.d.ts +25 -0
  141. package/lib/components/ContextMenu.d.ts.map +1 -0
  142. package/lib/components/ContextMenu.js +122 -0
  143. package/lib/components/ContextMenu.js.map +1 -0
  144. package/lib/components/Icon.d.ts +17 -0
  145. package/lib/components/Icon.d.ts.map +1 -0
  146. package/lib/components/Icon.js +19 -0
  147. package/lib/components/Icon.js.map +1 -0
  148. package/lib/components/LucideIcon.d.ts +10 -0
  149. package/lib/components/LucideIcon.d.ts.map +1 -0
  150. package/lib/components/LucideIcon.js +118 -0
  151. package/lib/components/LucideIcon.js.map +1 -0
  152. package/lib/components/MarkdownMessageText.d.ts +19 -0
  153. package/lib/components/MarkdownMessageText.d.ts.map +1 -0
  154. package/lib/components/MarkdownMessageText.js +35 -0
  155. package/lib/components/MarkdownMessageText.js.map +1 -0
  156. package/lib/components/MediaCard.d.ts +19 -0
  157. package/lib/components/MediaCard.d.ts.map +1 -0
  158. package/lib/components/MediaCard.js +102 -0
  159. package/lib/components/MediaCard.js.map +1 -0
  160. package/lib/components/MediaControls.d.ts +41 -0
  161. package/lib/components/MediaControls.d.ts.map +1 -0
  162. package/lib/components/MediaControls.js +523 -0
  163. package/lib/components/MediaControls.js.map +1 -0
  164. package/lib/components/MessageReply.d.ts.map +1 -1
  165. package/lib/components/MessageReply.js +11 -9
  166. package/lib/components/MessageReply.js.map +1 -1
  167. package/lib/components/ReplyPreview.d.ts +3 -1
  168. package/lib/components/ReplyPreview.d.ts.map +1 -1
  169. package/lib/components/ReplyPreview.js +36 -36
  170. package/lib/components/ReplyPreview.js.map +1 -1
  171. package/lib/components/SendIcon.d.ts +13 -0
  172. package/lib/components/SendIcon.d.ts.map +1 -0
  173. package/lib/components/SendIcon.js +37 -0
  174. package/lib/components/SendIcon.js.map +1 -0
  175. package/lib/components/Ticks.d.ts +25 -0
  176. package/lib/components/Ticks.d.ts.map +1 -0
  177. package/lib/components/Ticks.js +102 -0
  178. package/lib/components/Ticks.js.map +1 -0
  179. package/lib/components/VideoNoteOverlay.d.ts +25 -0
  180. package/lib/components/VideoNoteOverlay.d.ts.map +1 -0
  181. package/lib/components/VideoNoteOverlay.js +151 -0
  182. package/lib/components/VideoNoteOverlay.js.map +1 -0
  183. package/lib/components/VideoNoteRecorder.d.ts +19 -0
  184. package/lib/components/VideoNoteRecorder.d.ts.map +1 -0
  185. package/lib/components/VideoNoteRecorder.js +634 -0
  186. package/lib/components/VideoNoteRecorder.js.map +1 -0
  187. package/lib/components/VideoRecordButton.d.ts +29 -0
  188. package/lib/components/VideoRecordButton.d.ts.map +1 -0
  189. package/lib/components/VideoRecordButton.js +117 -0
  190. package/lib/components/VideoRecordButton.js.map +1 -0
  191. package/lib/components/VoiceMessageInput.d.ts +33 -0
  192. package/lib/components/VoiceMessageInput.d.ts.map +1 -0
  193. package/lib/components/VoiceMessageInput.js +396 -0
  194. package/lib/components/VoiceMessageInput.js.map +1 -0
  195. package/lib/components/WaveformPlayer.d.ts +19 -0
  196. package/lib/components/WaveformPlayer.d.ts.map +1 -0
  197. package/lib/components/WaveformPlayer.js +367 -0
  198. package/lib/components/WaveformPlayer.js.map +1 -0
  199. package/lib/components/mediaPalette.d.ts +23 -0
  200. package/lib/components/mediaPalette.d.ts.map +1 -0
  201. package/lib/components/mediaPalette.js +16 -0
  202. package/lib/components/mediaPalette.js.map +1 -0
  203. package/lib/components/mediaPlayback.d.ts +22 -0
  204. package/lib/components/mediaPlayback.d.ts.map +1 -0
  205. package/lib/components/mediaPlayback.js +34 -0
  206. package/lib/components/mediaPlayback.js.map +1 -0
  207. package/lib/hooks/useColorScheme.d.ts +9 -2
  208. package/lib/hooks/useColorScheme.d.ts.map +1 -1
  209. package/lib/hooks/useColorScheme.js +9 -3
  210. package/lib/hooks/useColorScheme.js.map +1 -1
  211. package/lib/hooks/useHasKeyboardProvider.d.ts +19 -0
  212. package/lib/hooks/useHasKeyboardProvider.d.ts.map +1 -0
  213. package/lib/hooks/useHasKeyboardProvider.js +31 -0
  214. package/lib/hooks/useHasKeyboardProvider.js.map +1 -0
  215. package/lib/hooks/useIcons.d.ts +4 -0
  216. package/lib/hooks/useIcons.d.ts.map +1 -0
  217. package/lib/hooks/useIcons.js +8 -0
  218. package/lib/hooks/useIcons.js.map +1 -0
  219. package/lib/hooks/useIsKeyboardVisible.d.ts +12 -0
  220. package/lib/hooks/useIsKeyboardVisible.d.ts.map +1 -0
  221. package/lib/hooks/useIsKeyboardVisible.js +31 -0
  222. package/lib/hooks/useIsKeyboardVisible.js.map +1 -0
  223. package/lib/hooks/useKeyboardVerticalOffset.d.ts +28 -0
  224. package/lib/hooks/useKeyboardVerticalOffset.d.ts.map +1 -0
  225. package/lib/hooks/useKeyboardVerticalOffset.js +43 -0
  226. package/lib/hooks/useKeyboardVerticalOffset.js.map +1 -0
  227. package/lib/hooks/useLabels.d.ts +4 -0
  228. package/lib/hooks/useLabels.d.ts.map +1 -0
  229. package/lib/hooks/useLabels.js +8 -0
  230. package/lib/hooks/useLabels.js.map +1 -0
  231. package/lib/hooks/useTheme.d.ts +21 -0
  232. package/lib/hooks/useTheme.d.ts.map +1 -0
  233. package/lib/hooks/useTheme.js +32 -0
  234. package/lib/hooks/useTheme.js.map +1 -0
  235. package/lib/i18n.d.ts +59 -0
  236. package/lib/i18n.d.ts.map +1 -0
  237. package/lib/i18n.js +122 -0
  238. package/lib/i18n.js.map +1 -0
  239. package/lib/index.d.ts +17 -0
  240. package/lib/index.d.ts.map +1 -1
  241. package/lib/index.js +17 -0
  242. package/lib/index.js.map +1 -1
  243. package/lib/types.d.ts +2 -1
  244. package/lib/types.d.ts.map +1 -1
  245. package/package.json +103 -41
  246. package/lib/MessageReply.d.ts +0 -15
  247. package/lib/MessageReply.d.ts.map +0 -1
  248. package/lib/MessageReply.js +0 -102
  249. package/lib/MessageReply.js.map +0 -1
  250. package/lib/ReplyPreview.d.ts +0 -14
  251. package/lib/ReplyPreview.d.ts.map +0 -1
  252. package/lib/ReplyPreview.js +0 -94
  253. package/lib/ReplyPreview.js.map +0 -1
@@ -1,18 +1,18 @@
1
1
  import { StyleSheet } from 'react-native';
2
2
  export default StyleSheet.create({
3
+ // The row spans the full width so a long-press anywhere beside the bubble
4
+ // still opens the reactions / context menu (Telegram-style). The 70% cap
5
+ // lives on the bubble itself (see `wrapper` in Bubble/styles).
3
6
  container: {
4
7
  flexDirection: 'row',
5
8
  alignItems: 'flex-end',
6
- maxWidth: '70%',
9
+ marginHorizontal: 8,
7
10
  },
8
11
  container_left: {
9
12
  justifyContent: 'flex-start',
10
- marginLeft: 8,
11
13
  },
12
14
  container_right: {
13
15
  justifyContent: 'flex-end',
14
- marginRight: 8,
15
- alignSelf: 'flex-end',
16
16
  },
17
17
  });
18
18
  //# sourceMappingURL=styles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/Message/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,eAAe,UAAU,CAAC,MAAM,CAAC;IAC/B,SAAS,EAAE;QACT,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,UAAU;QACtB,QAAQ,EAAE,KAAK;KAChB;IACD,cAAc,EAAE;QACd,cAAc,EAAE,YAAY;QAC5B,UAAU,EAAE,CAAC;KACd;IACD,eAAe,EAAE;QACf,cAAc,EAAE,UAAU;QAC1B,WAAW,EAAE,CAAC;QACd,SAAS,EAAE,UAAU;KACtB;CACF,CAAC,CAAA"}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../src/Message/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,eAAe,UAAU,CAAC,MAAM,CAAC;IAC/B,0EAA0E;IAC1E,yEAAyE;IACzE,+DAA+D;IAC/D,SAAS,EAAE;QACT,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,UAAU;QACtB,gBAAgB,EAAE,CAAC;KACpB;IACD,cAAc,EAAE;QACd,cAAc,EAAE,YAAY;KAC7B;IACD,eAAe,EAAE;QACf,cAAc,EAAE,UAAU;KAC3B;CACF,CAAC,CAAA"}
@@ -1,3 +1,4 @@
1
1
  import React from 'react';
2
- export declare function MessageAudio(): React.JSX.Element;
2
+ import { IMessage, MessageAudioProps } from './Models';
3
+ export declare function MessageAudio<TMessage extends IMessage = IMessage>({ currentMessage, position, containerStyle, audioStyle, }: Partial<MessageAudioProps<TMessage>>): React.JSX.Element | null;
3
4
  //# sourceMappingURL=MessageAudio.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageAudio.d.ts","sourceRoot":"","sources":["../src/MessageAudio.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAA;AActC,wBAAgB,YAAY,sBAa3B"}
1
+ {"version":3,"file":"MessageAudio.d.ts","sourceRoot":"","sources":["../src/MessageAudio.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsB,MAAM,OAAO,CAAA;AAQ1C,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAwEtD,wBAAgB,YAAY,CAAC,QAAQ,SAAS,QAAQ,GAAG,QAAQ,EAAG,EAClE,cAAc,EACd,QAAiB,EACjB,cAAc,EACd,UAAU,GACX,EAAE,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,4BAetC"}
@@ -1,24 +1,126 @@
1
- import React, { useMemo } from 'react';
2
- import { View, StyleSheet, Text } from 'react-native';
3
- import { Color } from './Color';
1
+ import React, { useCallback } from 'react';
2
+ import { Pressable, StyleSheet, Text, View } from 'react-native';
3
+ import { Icon } from './components/Icon';
4
+ import { MediaCard } from './components/MediaCard';
5
+ import { PauseIcon, PlayIcon } from './components/MediaControls';
6
+ import { getMediaPalette } from './components/mediaPalette';
7
+ import { WaveformPlayer, isWaveformAvailable } from './components/WaveformPlayer';
8
+ import { useThemedStyles } from './hooks/useTheme';
9
+ // Optional inline player. Resolved through a try/catch require so the bundle
10
+ // works whether or not the consumer installed `expo-audio` (Metro treats
11
+ // try/catch-wrapped requires as optional dependencies). When present, audio
12
+ // messages get a real play/pause control with a progress bar; otherwise they
13
+ // fall back to a tappable MediaCard that opens the audio in the system player.
14
+ let expoAudio = null;
15
+ try {
16
+ expoAudio = require('expo-audio');
17
+ }
18
+ catch {
19
+ expoAudio = null;
20
+ }
21
+ const isExpoAudioAvailable = !!(expoAudio?.useAudioPlayer && expoAudio?.useAudioPlayerStatus);
22
+ const formatTime = (seconds) => {
23
+ if (!Number.isFinite(seconds) || seconds < 0)
24
+ seconds = 0;
25
+ const mins = Math.floor(seconds / 60);
26
+ const secs = Math.floor(seconds % 60);
27
+ return `${mins}:${secs.toString().padStart(2, '0')}`;
28
+ };
29
+ // Only mounted when expo-audio resolved, so the hooks below always run in a
30
+ // stable order.
31
+ const ExpoAudioPlayer = ({ uri, position }) => {
32
+ const player = expoAudio.useAudioPlayer(uri);
33
+ const status = expoAudio.useAudioPlayerStatus(player);
34
+ const styles = useThemedStyles(position === 'right' ? createRightStyles : createLeftStyles);
35
+ const isPlaying = !!status?.playing;
36
+ const duration = status?.duration ?? 0;
37
+ const currentTime = status?.currentTime ?? 0;
38
+ const progress = duration > 0 ? Math.min(1, currentTime / duration) : 0;
39
+ const togglePlayback = useCallback(() => {
40
+ if (status?.playing) {
41
+ player.pause();
42
+ }
43
+ else {
44
+ if (status?.didJustFinish || (duration > 0 && currentTime >= duration))
45
+ player.seekTo(0);
46
+ player.play();
47
+ }
48
+ }, [player, status, duration, currentTime]);
49
+ return (<View style={styles.audioRow}>
50
+ <Pressable onPress={togglePlayback} accessibilityRole='button' accessibilityLabel={isPlaying ? 'pause' : 'play'} style={styles.playCircle}>
51
+ {isPlaying
52
+ ? <Icon name='pause' color={styles.glyphColor.color} size={14} fallback={<PauseIcon color={styles.glyphColor.color} size={14}/>}/>
53
+ : <Icon name='play' color={styles.glyphColor.color} size={14} fallback={<PlayIcon color={styles.glyphColor.color} size={14}/>}/>}
54
+ </Pressable>
55
+ <View style={styles.track}>
56
+ {/* progress fill width is a runtime value, so it stays inline */}
57
+ <View style={[styles.trackFill, { width: `${progress * 100}%` }]}/>
58
+ </View>
59
+ <Text style={styles.time}>
60
+ {formatTime(currentTime > 0 ? currentTime : duration)}
61
+ </Text>
62
+ </View>);
63
+ };
64
+ export function MessageAudio({ currentMessage, position = 'left', containerStyle, audioStyle, }) {
65
+ const uri = currentMessage?.audio;
66
+ if (!uri)
67
+ return null;
68
+ return (<View style={[styles.container, containerStyle]}>
69
+ {isWaveformAvailable
70
+ ? <WaveformPlayer uri={uri} position={position} duration={currentMessage?.duration}/>
71
+ : isExpoAudioAvailable
72
+ ? <ExpoAudioPlayer uri={uri} position={position}/>
73
+ : <MediaCard kind='audio' uri={uri} position={position} style={audioStyle}/>}
74
+ </View>);
75
+ }
76
+ const makeStyles = (theme, position) => {
77
+ const palette = getMediaPalette(theme, position);
78
+ return StyleSheet.create({
79
+ // Carries the glyph color out of JSX and into the stylesheet.
80
+ glyphColor: {
81
+ color: palette.glyph,
82
+ },
83
+ audioRow: {
84
+ flexDirection: 'row',
85
+ alignItems: 'center',
86
+ paddingVertical: 6,
87
+ paddingHorizontal: 8,
88
+ minWidth: 200,
89
+ gap: 10,
90
+ },
91
+ playCircle: {
92
+ width: 36,
93
+ height: 36,
94
+ borderRadius: 18,
95
+ backgroundColor: palette.control,
96
+ alignItems: 'center',
97
+ justifyContent: 'center',
98
+ },
99
+ track: {
100
+ flex: 1,
101
+ height: 3,
102
+ borderRadius: 2,
103
+ backgroundColor: palette.track,
104
+ overflow: 'hidden',
105
+ },
106
+ trackFill: {
107
+ height: 3,
108
+ borderRadius: 2,
109
+ backgroundColor: palette.progress,
110
+ },
111
+ time: {
112
+ fontSize: 12,
113
+ color: palette.meta,
114
+ minWidth: 34,
115
+ textAlign: 'right',
116
+ },
117
+ });
118
+ };
119
+ const createLeftStyles = (theme) => makeStyles(theme, 'left');
120
+ const createRightStyles = (theme) => makeStyles(theme, 'right');
4
121
  const styles = StyleSheet.create({
5
122
  container: {
6
- padding: 10,
7
- },
8
- text: {
9
- color: Color.alizarin,
10
- fontWeight: '600',
123
+ overflow: 'hidden',
11
124
  },
12
125
  });
13
- export function MessageAudio() {
14
- const content = useMemo(() => (<View style={styles.container}>
15
- <Text style={styles.text}>
16
- {'Audio is not implemented by Chat.'}
17
- </Text>
18
- <Text style={styles.text}>
19
- {'\nYou need to provide your own implementation by using renderMessageAudio prop.'}
20
- </Text>
21
- </View>), []);
22
- return content;
23
- }
24
126
  //# sourceMappingURL=MessageAudio.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageAudio.js","sourceRoot":"","sources":["../src/MessageAudio.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAG,IAAI,EAAE,MAAM,cAAc,CAAA;AACtD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAE/B,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,SAAS,EAAE;QACT,OAAO,EAAE,EAAE;KACZ;IACD,IAAI,EAAE;QACJ,KAAK,EAAE,KAAK,CAAC,QAAQ;QACrB,UAAU,EAAE,KAAK;KAClB;CACF,CAAC,CAAA;AAEF,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAC5B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CACvB;QAAA,CAAC,mCAAmC,CACtC;MAAA,EAAE,IAAI,CACN;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CACvB;QAAA,CAAC,iFAAiF,CACpF;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,IAAI,CAAC,CACR,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,OAAO,CAAA;AAChB,CAAC"}
1
+ {"version":3,"file":"MessageAudio.js","sourceRoot":"","sources":["../src/MessageAudio.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import { IMessage, MessageLocationProps } from './Models';
3
+ /**
4
+ * Default renderer for location messages. Dependency-free: shows a styled map
5
+ * card and opens the coordinates in the system maps app on tap (override via
6
+ * the `onPress` prop or `renderMessageLocation`).
7
+ */
8
+ export declare function MessageLocation<TMessage extends IMessage = IMessage>({ currentMessage, position, containerStyle, locationStyle, onPress, }: Partial<MessageLocationProps<TMessage>>): React.JSX.Element | null;
9
+ //# sourceMappingURL=MessageLocation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageLocation.d.ts","sourceRoot":"","sources":["../src/MessageLocation.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsB,MAAM,OAAO,CAAA;AAM1C,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAUzD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,SAAS,QAAQ,GAAG,QAAQ,EAAG,EACrE,cAAc,EACd,QAAiB,EACjB,cAAc,EACd,aAAa,EACb,OAAO,GACR,EAAE,OAAO,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC,4BAyCzC"}
@@ -0,0 +1,85 @@
1
+ import React, { useCallback } from 'react';
2
+ import { Linking, Platform, Pressable, StyleSheet, Text, View } from 'react-native';
3
+ import { Icon } from './components/Icon';
4
+ import { PinIcon } from './components/MediaControls';
5
+ import { useLabels } from './hooks/useLabels';
6
+ import { useThemedStyles } from './hooks/useTheme';
7
+ const buildMapsUrl = (latitude, longitude) => Platform.select({
8
+ ios: `https://maps.apple.com/?ll=${latitude},${longitude}&q=${latitude},${longitude}`,
9
+ android: `geo:${latitude},${longitude}?q=${latitude},${longitude}`,
10
+ default: `https://www.google.com/maps/search/?api=1&query=${latitude},${longitude}`,
11
+ });
12
+ /**
13
+ * Default renderer for location messages. Dependency-free: shows a styled map
14
+ * card and opens the coordinates in the system maps app on tap (override via
15
+ * the `onPress` prop or `renderMessageLocation`).
16
+ */
17
+ export function MessageLocation({ currentMessage, position = 'left', containerStyle, locationStyle, onPress, }) {
18
+ const styles = useThemedStyles(position === 'right' ? createRightStyles : createLeftStyles);
19
+ const labels = useLabels();
20
+ const location = currentMessage?.location;
21
+ const handlePress = useCallback(() => {
22
+ if (!location)
23
+ return;
24
+ if (onPress) {
25
+ onPress(location);
26
+ return;
27
+ }
28
+ Linking.openURL(buildMapsUrl(location.latitude, location.longitude)).catch(() => { });
29
+ }, [location, onPress]);
30
+ if (!location)
31
+ return null;
32
+ const coords = `${location.latitude.toFixed(5)}, ${location.longitude.toFixed(5)}`;
33
+ return (<View style={[styles.container, containerStyle]}>
34
+ <Pressable onPress={handlePress} accessibilityRole='button' accessibilityLabel={labels.openLocationAccessibility} style={[styles.card, locationStyle]}>
35
+ <View style={styles.map}>
36
+ <Icon name='pin' color='#fff' size={26} fallback={<PinIcon color='#fff' size={26}/>}/>
37
+ </View>
38
+ <View style={styles.meta}>
39
+ <Text style={styles.title} numberOfLines={1}>{labels.location}</Text>
40
+ <Text style={styles.coords} numberOfLines={1}>{coords}</Text>
41
+ </View>
42
+ </Pressable>
43
+ </View>);
44
+ }
45
+ const makeStyles = (theme, position) => {
46
+ const overlay = position === 'right' ? theme.colors.outgoingOverlay : theme.colors.reactionBackground;
47
+ const titleColor = position === 'right' ? theme.colors.outgoingText : theme.colors.incomingText;
48
+ const metaColor = position === 'right' ? theme.colors.outgoingMeta : theme.colors.incomingMeta;
49
+ return StyleSheet.create({
50
+ container: {
51
+ overflow: 'hidden',
52
+ },
53
+ card: {
54
+ width: 220,
55
+ borderRadius: 12,
56
+ overflow: 'hidden',
57
+ margin: 6,
58
+ backgroundColor: overlay,
59
+ },
60
+ map: {
61
+ height: 110,
62
+ alignItems: 'center',
63
+ justifyContent: 'center',
64
+ backgroundColor: theme.colors.accent,
65
+ opacity: 0.85,
66
+ },
67
+ meta: {
68
+ paddingHorizontal: 12,
69
+ paddingVertical: 8,
70
+ },
71
+ title: {
72
+ fontSize: 14,
73
+ fontWeight: '600',
74
+ color: titleColor,
75
+ },
76
+ coords: {
77
+ marginTop: 2,
78
+ fontSize: 12,
79
+ color: metaColor,
80
+ },
81
+ });
82
+ };
83
+ const createLeftStyles = (theme) => makeStyles(theme, 'left');
84
+ const createRightStyles = (theme) => makeStyles(theme, 'right');
85
+ //# sourceMappingURL=MessageLocation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MessageLocation.js","sourceRoot":"","sources":["../src/MessageLocation.tsx"],"names":[],"mappings":"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"}
@@ -19,6 +19,17 @@ export type MessageTextProps<TMessage extends IMessage> = {
19
19
  hashtagUrl?: string;
20
20
  mentionUrl?: string;
21
21
  stripPrefix?: boolean;
22
+ /**
23
+ * Render the message body as markdown (great for AI/streamed replies). `true`
24
+ * forces markdown for every message, `false` disables it; when left unset,
25
+ * streamed messages render as markdown automatically. Uses the optional
26
+ * `react-native-streamdown` peer when installed (best handling of
27
+ * streaming-incomplete markdown), otherwise a built-in dependency-free renderer
28
+ * covering headings, lists, blockquotes, code, bold/italic/strikethrough and links.
29
+ */
30
+ markdown?: boolean;
31
+ /** Extra props forwarded to the Streamdown component (its own theming/rules API); only used when streamdown is installed. */
32
+ markdownProps?: Record<string, unknown>;
22
33
  };
23
- export declare function MessageText<TMessage extends IMessage>({ currentMessage, position, containerStyle, textStyle, linkStyle: linkStyleProp, customTextStyle, onPress: onPressProp, matchers, email, phone, url, hashtag, mention, hashtagUrl, mentionUrl, stripPrefix, }: MessageTextProps<TMessage>): React.JSX.Element;
34
+ export declare function MessageText<TMessage extends IMessage>({ currentMessage, position, containerStyle, textStyle, linkStyle: linkStyleProp, customTextStyle, onPress: onPressProp, matchers, email, phone, url, hashtag, mention, hashtagUrl, mentionUrl, stripPrefix, markdown, markdownProps, }: MessageTextProps<TMessage>): React.JSX.Element;
24
35
  //# sourceMappingURL=MessageText.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageText.d.ts","sourceRoot":"","sources":["../src/MessageText.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+B,MAAM,OAAO,CAAA;AACnD,OAAO,EAEL,SAAS,EACT,SAAS,EACT,SAAS,EAEH,MAAM,cAAc,CAAA;AAG5B,OAAO,EAAc,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAEnD,MAAM,MAAM,gBAAgB,CAAC,QAAQ,SAAS,QAAQ,IAAI;IACxD,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,cAAc,EAAE,QAAQ,CAAA;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;IAC1C,SAAS,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;IACrC,SAAS,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;IACrC,eAAe,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IACtC,OAAO,CAAC,EAAE,CACR,OAAO,EAAE,QAAQ,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,QAAQ,KACX,IAAI,CAAA;IAET,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;IACxB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AAED,wBAAgB,WAAW,CAAC,QAAQ,SAAS,QAAQ,EAAE,EACrD,cAAc,EACd,QAAiB,EACjB,cAAc,EACd,SAAS,EACT,SAAS,EAAE,aAAa,EACxB,eAAe,EACf,OAAO,EAAE,WAAW,EACpB,QAAQ,EACR,KAAY,EACZ,KAAY,EACZ,GAAU,EACV,OAAe,EACf,OAAe,EACf,UAAU,EACV,UAAU,EACV,WAAmB,GACpB,EAAE,gBAAgB,CAAC,QAAQ,CAAC,qBAmD5B"}
1
+ {"version":3,"file":"MessageText.d.ts","sourceRoot":"","sources":["../src/MessageText.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA+B,MAAM,OAAO,CAAA;AACnD,OAAO,EAEL,SAAS,EACT,SAAS,EACT,SAAS,EAEH,MAAM,cAAc,CAAA;AAM5B,OAAO,EAAc,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAChE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAGnD,MAAM,MAAM,gBAAgB,CAAC,QAAQ,SAAS,QAAQ,IAAI;IACxD,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,cAAc,EAAE,QAAQ,CAAA;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;IAC1C,SAAS,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;IACrC,SAAS,CAAC,EAAE,cAAc,CAAC,SAAS,CAAC,CAAA;IACrC,eAAe,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;IACtC,OAAO,CAAC,EAAE,CACR,OAAO,EAAE,QAAQ,EACjB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,QAAQ,KACX,IAAI,CAAA;IAET,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;IACxB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,6HAA6H;IAC7H,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACxC,CAAA;AAED,wBAAgB,WAAW,CAAC,QAAQ,SAAS,QAAQ,EAAE,EACrD,cAAc,EACd,QAAiB,EACjB,cAAc,EACd,SAAS,EACT,SAAS,EAAE,aAAa,EACxB,eAAe,EACf,OAAO,EAAE,WAAW,EACpB,QAAQ,EACR,KAAY,EACZ,KAAY,EACZ,GAAU,EACV,OAAe,EACf,OAAe,EACf,UAAU,EACV,UAAU,EACV,WAAmB,EACnB,QAAQ,EACR,aAAa,GACd,EAAE,gBAAgB,CAAC,QAAQ,CAAC,qBA8F5B"}
@@ -1,23 +1,46 @@
1
1
  import React, { useMemo, useCallback } from 'react';
2
2
  import { StyleSheet, View, Text } from 'react-native';
3
+ import { BasicMarkdown } from './components/BasicMarkdown';
4
+ import { MarkdownMessageText, isMarkdownAvailable } from './components/MarkdownMessageText';
3
5
  import { StreamingCursor } from './components/StreamingCursor';
6
+ import { useThemedStyles } from './hooks/useTheme';
4
7
  import { LinkParser } from './linkParser';
5
- export function MessageText({ currentMessage, position = 'left', containerStyle, textStyle, linkStyle: linkStyleProp, customTextStyle, onPress: onPressProp, matchers, email = true, phone = true, url = true, hashtag = false, mention = false, hashtagUrl, mentionUrl, stripPrefix = false, }) {
8
+ export function MessageText({ currentMessage, position = 'left', containerStyle, textStyle, linkStyle: linkStyleProp, customTextStyle, onPress: onPressProp, matchers, email = true, phone = true, url = true, hashtag = false, mention = false, hashtagUrl, mentionUrl, stripPrefix = false, markdown, markdownProps, }) {
9
+ const styles = useThemedStyles(createStyles);
6
10
  const linkStyle = useMemo(() => StyleSheet.flatten([
7
11
  styles.link,
12
+ position === 'left' && styles.link_left,
8
13
  linkStyleProp?.[position],
9
- ]), [position, linkStyleProp]);
14
+ ]), [styles, position, linkStyleProp]);
10
15
  const style = useMemo(() => [
16
+ styles.text,
11
17
  styles[`text_${position}`],
12
18
  textStyle?.[position],
13
19
  customTextStyle,
14
- ], [position, textStyle, customTextStyle]);
20
+ ], [styles, position, textStyle, customTextStyle]);
15
21
  const handlePress = useCallback((url, type) => {
16
22
  onPressProp?.(currentMessage, url, type);
17
23
  }, [onPressProp, currentMessage]);
18
24
  const isStreaming = !!currentMessage?.streaming;
25
+ // Render markdown when explicitly enabled, or when the message is being
26
+ // streamed (AI replies) and it wasn't explicitly disabled. Prefer
27
+ // react-native-streamdown when installed (best streaming-incomplete handling),
28
+ // otherwise fall back to the built-in dependency-free renderer.
29
+ const wantMarkdown = markdown !== false && (markdown === true || isStreaming);
30
+ if (wantMarkdown && isMarkdownAvailable)
31
+ return (<MarkdownMessageText text={currentMessage.text} isStreaming={isStreaming} textStyle={style} containerStyle={[styles.container, containerStyle?.[position]]} componentProps={markdownProps}/>);
32
+ if (wantMarkdown)
33
+ return (<View style={[styles.container, containerStyle?.[position]]}>
34
+ <BasicMarkdown text={currentMessage.text} textStyle={style} linkStyle={linkStyle} onLinkPress={onPressProp ? (link) => handlePress(link, 'url') : undefined}/>
35
+ {isStreaming && (<Text style={style}>
36
+ <StreamingCursor />
37
+ </Text>)}
38
+ </View>);
19
39
  const parsed = (<LinkParser text={currentMessage.text} matchers={matchers} email={email} phone={phone} url={url} hashtag={hashtag} mention={mention} hashtagUrl={hashtagUrl} mentionUrl={mentionUrl} stripPrefix={stripPrefix} linkStyle={linkStyle} textStyle={style} onPress={onPressProp ? handlePress : undefined} TextComponent={Text}/>);
20
- return (<View style={[styles.container, containerStyle?.[position]]}>
40
+ return (<View style={[
41
+ styles.container,
42
+ containerStyle?.[position],
43
+ ]}>
21
44
  {isStreaming
22
45
  ? (
23
46
  // Wrap in a Text so the caret flows inline after the last word and
@@ -29,23 +52,27 @@ export function MessageText({ currentMessage, position = 'left', containerStyle,
29
52
  : parsed}
30
53
  </View>);
31
54
  }
32
- const styles = StyleSheet.create({
55
+ const createStyles = (theme) => StyleSheet.create({
33
56
  container: {
34
- marginVertical: 5,
35
- marginHorizontal: 10,
57
+ marginVertical: theme.spacing.bubblePaddingV,
58
+ marginHorizontal: theme.spacing.bubblePaddingH,
36
59
  },
37
60
  text: {
38
- fontSize: 16,
39
- lineHeight: 20,
61
+ fontSize: theme.typography.message.fontSize,
62
+ lineHeight: theme.typography.message.lineHeight,
63
+ fontWeight: theme.typography.message.fontWeight,
40
64
  },
41
65
  text_left: {
42
- color: 'black',
66
+ color: theme.colors.incomingText,
43
67
  },
44
68
  text_right: {
45
- color: 'white',
69
+ color: theme.colors.outgoingText,
46
70
  },
47
71
  link: {
48
72
  textDecorationLine: 'underline',
49
73
  },
74
+ link_left: {
75
+ color: theme.colors.accent,
76
+ },
50
77
  });
51
78
  //# sourceMappingURL=MessageText.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageText.js","sourceRoot":"","sources":["../src/MessageText.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"MessageText.js","sourceRoot":"","sources":["../src/MessageText.tsx"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  import React from 'react';
2
- export declare function MessageVideo(): React.JSX.Element;
2
+ import { IMessage, MessageVideoProps } from './Models';
3
+ export declare function MessageVideo<TMessage extends IMessage = IMessage>({ currentMessage, position, containerStyle, videoStyle, videoProps, }: Partial<MessageVideoProps<TMessage>>): React.JSX.Element | null;
3
4
  //# sourceMappingURL=MessageVideo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageVideo.d.ts","sourceRoot":"","sources":["../src/MessageVideo.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAA;AActC,wBAAgB,YAAY,sBAa3B"}
1
+ {"version":3,"file":"MessageVideo.d.ts","sourceRoot":"","sources":["../src/MessageVideo.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA0D,MAAM,OAAO,CAAA;AAK9E,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA2JtD,wBAAgB,YAAY,CAAC,QAAQ,SAAS,QAAQ,GAAG,QAAQ,EAAG,EAClE,cAAc,EACd,QAAiB,EACjB,cAAc,EACd,UAAU,EACV,UAAU,GACX,EAAE,OAAO,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,4BAoCtC"}
@@ -1,24 +1,162 @@
1
- import React, { useMemo } from 'react';
2
- import { View, StyleSheet, Text } from 'react-native';
3
- import { Color } from './Color';
1
+ import React, { useCallback, useEffect, useId, useRef, useState } from 'react';
2
+ import { Pressable, StyleSheet, View, useWindowDimensions } from 'react-native';
3
+ import { MediaCard } from './components/MediaCard';
4
+ import { claimPlayback, releasePlayback } from './components/mediaPlayback';
5
+ import { VideoNoteMeta, VideoNoteOverlay } from './components/VideoNoteOverlay';
6
+ // Optional inline player. Resolved through a try/catch require so the bundle
7
+ // works whether or not the consumer installed `expo-video` - Metro treats
8
+ // try/catch-wrapped requires as optional dependencies and won't fail the build
9
+ // when the module is absent. When present, messages render a real inline
10
+ // player; otherwise they fall back to a tappable MediaCard.
11
+ let expoVideo = null;
12
+ try {
13
+ expoVideo = require('expo-video');
14
+ }
15
+ catch {
16
+ expoVideo = null;
17
+ }
18
+ const isExpoVideoAvailable = !!(expoVideo?.VideoView && expoVideo?.useVideoPlayer);
19
+ // A Telegram round note is sized from the screen, not a fixed puck.
20
+ const NOTE_WIDTH_RATIO = 0.62;
21
+ const MAX_NOTE_SIZE = 260;
22
+ // Only mounted when expo-video resolved, so the hooks below are always called
23
+ // in a stable order.
24
+ const ExpoVideoPlayer = ({ uri, style, videoProps, isNote, duration, noteSize }) => {
25
+ const player = expoVideo.useVideoPlayer(uri, (p) => {
26
+ // A note holds its first frame muted. It does NOT autoplay: every note in
27
+ // the list would otherwise decode and loop at once, and there would be no
28
+ // way to ever hear one.
29
+ p.loop = false;
30
+ if (isNote)
31
+ p.muted = true;
32
+ });
33
+ const VideoView = expoVideo.VideoView;
34
+ const [isPlaying, setIsPlaying] = useState(false);
35
+ const [isMuted, setIsMuted] = useState(true);
36
+ const [progress, setProgress] = useState(0);
37
+ // A note counts as watched once it has been played through at least once.
38
+ const [isWatched, setIsWatched] = useState(false);
39
+ const playerId = useId();
40
+ const rafRef = useRef(null);
41
+ const stopRaf = useCallback(() => {
42
+ if (rafRef.current != null) {
43
+ cancelAnimationFrame(rafRef.current);
44
+ rafRef.current = null;
45
+ }
46
+ }, []);
47
+ const pause = useCallback(() => {
48
+ try {
49
+ player.pause();
50
+ }
51
+ catch {
52
+ // player already torn down
53
+ }
54
+ stopRaf();
55
+ setIsPlaying(false);
56
+ }, [player, stopRaf]);
57
+ // Drives the progress ring. expo-video has no per-frame callback, so the
58
+ // position is sampled on the display link while playing.
59
+ const tick = useCallback(() => {
60
+ const total = player.duration || duration || 0;
61
+ if (total > 0) {
62
+ const next = Math.min(1, (player.currentTime || 0) / total);
63
+ setProgress(next);
64
+ if (next >= 1) {
65
+ stopRaf();
66
+ releasePlayback(playerId);
67
+ setIsPlaying(false);
68
+ setProgress(0);
69
+ setIsMuted(true);
70
+ setIsWatched(true);
71
+ return;
72
+ }
73
+ }
74
+ rafRef.current = requestAnimationFrame(tick);
75
+ }, [player, duration, stopRaf, playerId]);
76
+ useEffect(() => () => {
77
+ stopRaf();
78
+ releasePlayback(playerId);
79
+ }, [stopRaf, playerId]);
80
+ // Tap a note to play it with sound, tap again to pause - the round note has no
81
+ // native controls, so this press target is its only affordance.
82
+ const togglePlayback = useCallback(() => {
83
+ if (!isNote)
84
+ return;
85
+ if (isPlaying) {
86
+ pause();
87
+ releasePlayback(playerId);
88
+ return;
89
+ }
90
+ player.muted = false;
91
+ setIsMuted(false);
92
+ if (progress <= 0)
93
+ player.currentTime = 0;
94
+ player.play();
95
+ setIsPlaying(true);
96
+ // Starting stops any other note or voice message, as Telegram does.
97
+ claimPlayback(playerId, pause);
98
+ stopRaf();
99
+ rafRef.current = requestAnimationFrame(tick);
100
+ }, [isNote, isPlaying, player, pause, playerId, tick, stopRaf, progress]);
101
+ const view = (<VideoView style={style} player={player} fullscreenOptions={{ enable: !isNote }} allowsPictureInPicture={!isNote} nativeControls={!isNote} contentFit='cover' {...videoProps}/>);
102
+ if (!isNote)
103
+ return view;
104
+ return (<View>
105
+ <Pressable onPress={togglePlayback} accessibilityRole='button' accessibilityLabel={isPlaying ? 'pause video note' : 'play video note'}>
106
+ {view}
107
+ <VideoNoteOverlay size={noteSize} progress={progress} isMuted={isMuted} isPlaying={isPlaying}/>
108
+ </Pressable>
109
+ {/* Telegram puts the length under the circle, on the chat background. */}
110
+ <VideoNoteMeta duration={duration} isWatched={isWatched}/>
111
+ </View>);
112
+ };
113
+ export function MessageVideo({ currentMessage, position = 'left', containerStyle, videoStyle, videoProps, }) {
114
+ const { width } = useWindowDimensions();
115
+ const noteSize = Math.min(width * NOTE_WIDTH_RATIO, MAX_NOTE_SIZE);
116
+ const uri = currentMessage?.video;
117
+ if (!uri)
118
+ return null;
119
+ const isNote = !!currentMessage?.videoNote;
120
+ const noteStyle = { width: noteSize, height: noteSize, borderRadius: noteSize / 2 };
121
+ return (<View style={[
122
+ styles.container,
123
+ isNote && styles.noteContainer,
124
+ // A note follows its sender's side; hardcoding flex-end detached an
125
+ // incoming note from the left edge of its row.
126
+ isNote && (position === 'right' ? styles.noteRight : styles.noteLeft),
127
+ containerStyle,
128
+ ]}>
129
+ {isExpoVideoAvailable
130
+ ? (<ExpoVideoPlayer uri={uri} style={[isNote ? [styles.note, noteStyle] : styles.video, videoStyle]} videoProps={videoProps} isNote={isNote} duration={currentMessage?.duration} noteSize={noteSize}/>)
131
+ : <MediaCard kind='video' uri={uri} position={position} style={[isNote && noteStyle, videoStyle]}/>}
132
+ </View>);
133
+ }
4
134
  const styles = StyleSheet.create({
5
135
  container: {
6
- padding: 10,
136
+ overflow: 'hidden',
137
+ },
138
+ // A round note floats without bubble chrome (the Bubble strips its
139
+ // background). It must not clip: the duration sits below the circle.
140
+ noteContainer: {
141
+ overflow: 'visible',
7
142
  },
8
- text: {
9
- color: Color.alizarin,
10
- fontWeight: '600',
143
+ noteLeft: {
144
+ alignSelf: 'flex-start',
145
+ },
146
+ noteRight: {
147
+ alignSelf: 'flex-end',
148
+ },
149
+ video: {
150
+ width: 220,
151
+ height: 140,
152
+ borderRadius: 12,
153
+ margin: 6,
154
+ // Dark placeholder so the bubble reads as a video while the first frame
155
+ // loads, instead of flashing a white void.
156
+ backgroundColor: '#000',
157
+ },
158
+ note: {
159
+ backgroundColor: '#000',
11
160
  },
12
161
  });
13
- export function MessageVideo() {
14
- const content = useMemo(() => (<View style={styles.container}>
15
- <Text style={styles.text}>
16
- {'Video is not implemented by Chat.'}
17
- </Text>
18
- <Text style={styles.text}>
19
- {'\nYou need to provide your own implementation by using renderMessageVideo prop.'}
20
- </Text>
21
- </View>), []);
22
- return content;
23
- }
24
162
  //# sourceMappingURL=MessageVideo.js.map